2017-11-28 15 views
2

IO [[Char]]IO()をバインドすることは可能ですが、MaybeIOでバインドすることはできません。誰かがこのリラクゼーションがいかに悪いデザインにつながるかの例を挙げることはできますか?モナド自体ではなく、多形型のモナドの自由が許可されるのはなぜですか?同じMonad型だけを `>> '演算子で連結できるようにする背景にある論理は何ですか?

+5

typeclassインスタンスが実際にサポートする操作しか使用できません。 'Monad'のインスタンスは'(>> =):: m a - >(a - > m b) - > m b'のみを供給します。つまり、全体的に同じ 'm 'を使用する必要があります。任意の "何にも縛られない"操作があるという賢明な意味がある場合は、それをタイプキャストとして指定し、あなたが知っている限り多くのインスタンスを作成することができます。 '(>> =):: m a - >(a - > n b) - > n b'のようなクラスは、コンシューマーの何も必要としないが、実装者にとっては分かりやすく満足することはほとんど不可能である。 –

+1

'Monad'型クラスの背後にある理論は、' m'が同じ関数子であることを要求します。このプロパティはIOを処理するための基礎として適しています。別のタイプに切り替えることで 'IO'から脱出することはできません。 – chepner

+1

あなたは 'たぶん'に 'IO'をバインドするのですか? 'IO'モナドは状態を変更しません。状態を変更する方法を記述します。 –

答えて

7

「これはなにがMonadなのか」などの理論的な理由がたくさんあります。しかし、ここから少し離れて実装の詳細を見てみましょう。

最初にオフ - Monadは魔法ではありません。それは単なる標準型クラスです。 Monadのインスタンスは、誰かが書き込むときにのみ作成されます。

このインスタンスの記述は、(>>)の動作を定義するものです。通常は(>>=)のデフォルト定義で暗黙的に行われていますが、それはちょうど(>>=)がより一般的な演算子であるという証拠であり、それを書くには(>>)と同じ決定をする必要があります。

より一般的な種類の演算子が異なる場合は、2つの質問に答える必要があります。まず、タイプは何ですか?第二に、実装を提供するにはどうしたらいいですか?あなたの質問から、希望するタイプが何であるかは、本当に明確ではありません。次のうちの1つです:

class Poly1 m n where 
    (>>) :: m a -> n b -> m b 

class Poly2 m n where 
    (>>) :: m a -> n b -> n b 

class Poly3 m n o | m n -> o where 
    (>>) :: m a -> n b -> o b 

これらのすべてを実装することができます。しかし、それらを実際に使用するためには、2つの本当に重要な要素を失います。

  1. 一緒に使用する予定のタイプのペアごとにインスタンスを作成する必要があります。これは、各タイプの単なるインスタンスよりもはるかに複雑な作業です。何か約nn^2
  2. 予測可能性が失われます。操作は何であるかですか?ここで理論と実践が交差するところです。 Monadの背後にある理論は、操作に多くの制限を設けています。これらの制限は「モナド法」と呼ばれています。それらはHaskellで検証する能力を超えていますが、それに従わないMonadインスタンスはバグであるとみなされます。最終的には、Monadの操作には直ちに直感を立てることができます。関係するすべてのタイプの詳細を調べることなく、それらを使用することができます。従属するプロパティーを知っているからです。私が提案したクラスはどれも、そのような保証はありません。あなたは彼らが何をしているのか分かりません。
0

私は私が正しくあなたの質問を理解していることを確認しないんだけど、それはあなたが[]IOを構成することができることと同じ意味でIO[]Maybeを構成するために間違いなく可能です。あなたが:tを使用してGHCiの中の種類を確認した場合、

getContents >>= return . lines 

はあなたにIO [String]を与える

。あなたは

  >>= return . map Text.Read.readMaybe 

を追加する場合はIO[]Maybeの組成物であるIO [Maybe a]の種類を取得します。

  >>= return . Data.Maybe.catMaybes 

に渡してIO [a]にフラット化することができます。次に、解析された有効な入力行のリストを、それを再度平坦化して出力を計算する関数に渡すかもしれません。

1 

2 
Ignore this! 
3 

印刷6:入力と、一緒にプログラム

import Text.Read (readMaybe) 
import Data.Maybe (catMaybes) 

main :: IO() 
main = getContents >>=     -- IO String 
     return . lines >>=     -- IO [String] 
     return . map readMaybe >>=   -- IO [Maybe Int] 
     return . catMaybes >>=    -- IO [Int] 
     return . (sum :: [Int] -> Int) >>= -- IO Int 
     print        -- IO() 

このパット

またIO (Maybe [String])Maybe [IO String]で作業することが可能であろう、など

あなたにも>>でこれを行うことができます。考えられる例:getContents >> (return . Just) Falseは入力を読み込み、無視してIO (Maybe Bool)を返します。

関連する問題