私はモナドを使い始めたばかりで、これらの 2 つの式の評価が異なる理由がわかりません。
ghci> [1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]
ghci> return ([1,2],['a','b'])
([1,2],"ab")
型が違うから挙動が違うのは当たり前
最初の式は次のように型チェックしますNum t => [(t, Char)]
(>>=) 内のモナドとして [] を使用することは、モナドが List モナドであり、List Monad
http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Listのコンテキストである必要があると推論することを意味します。 (>>=) は concatMap で、戻り値は (:[]) です。
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
と同じです
concatMap (\n -> concatMap (\ch -> [(n, ch)]) ['a', 'b']) [1,2]
返す[(1,'a'),(1,'b'),(2,'a'),(2,'b')]
あなたの2番目の例では、実際に起こっていることは
式の型はもう少し一般的です。
Prelude> :t return ([1,2],['a','b'])
return ([1,2],['a','b']) :: (Monad m, Num t) => m ([t], [Char])
GHCi で実行しているため、いくつかのことが起こります。GHCi は、非常に大きな特別な IO モナドと見なすことができます。したがって、モナドが指定されていないので、GHC が結果を出力しようとすると、この場合はm
モナドが必要になります。IO
t
もデフォルトで に設定さInteger
れているため、結果の式のタイプはです:: IO ([Integer], [Char])
。
たまたま、使用されているすべての型にShow
インスタンスがあるため、GHC はIO
アクションの実行結果を出力できます。この場合は (アクションが返されるため) 入力と同じです。
GHCiでは、を使用して式のタイプをインタラクティブに確認できます:t
。そうすることで、式のタイプが異なることがわかります。
ghci> :t [1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
:: (Num t) => [(t, Char)]
ghci> :t return ([1,2],['a','b'])
return ([1,2],['a','b']) :: (Num t, Monad m) => m ([t], [Char])
したがって、それらは異なる値を持ちます。
おそらく、への引数の中return
にモナドが存在することに混乱しているでしょう。ただし、そのタイプを見てください。
ghci> :t return
return :: Monad m => a -> m a
return
その引数については何も知りません。値、任意の値を取り、デフォルトのモナディックコンテキストに配置するだけです。
これらの式が評価されたときに何が起こるかを正確に理解するには、次のものが必要です。
これがモナドインスタンスです:
instance Monad [] where
m >>= k = foldr ((++) . k) [] m
m >> k = foldr ((++) . (\ _ -> k)) [] m
return x = [x]
fail _ = []
>>
(私たちはそれらを使用していないので、無視することができfail
ます。)
それでは、式を拡張してみましょう。
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
設定するm = [1, 2]
と、次のk = \n -> ['a','b'] >>= \ch -> return (n,ch)
ようになります。
foldr ((++) . (\n -> ['a','b'] >>= \ch -> return (n,ch))) [] [1,2]
今度は2番目を取り除くために>>=
、m = ['a', 'b']
そしてk = \ch -> return (n, ch)
:
foldr ((++) . (\n -> rest)) [] [1,2]
where
rest = foldr ((++) . (\ch -> return (n,ch))) [] ['a', 'b']
簡単にreturn
取り除くことができます:
foldr ((++) . (\n -> rest)) [] [1,2]
where
rest = foldr ((++) . (\ch -> [(n,ch)]) [] ['a', 'b']
一方、2番目の式の値:
return ([1,2],['a','b'])
にいるモナドによって異なります。リストモナドでは、単純に次のようになります。
[([1,2], ['a','b'])] :: [] ([Int], String)
一方、多分モナドでは、それは次のとおりです。
Just ([1,2], ['a', 'b']) :: Maybe ([Int], String)