3

私はモナドを使い始めたばかりで、これらの 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")
4

2 に答える 2

10

型が違うから挙動が違うのは当たり前

最初の式は次のように型チェックします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アクションの実行結果を出力できます。この場合は (アクションが返されるため) 入力と同じです。

于 2012-08-15T13:52:52.987 に答える
6

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その引数については何も知りません。値、任意の値を取り、デフォルトのモナディックコンテキストに配置するだけです。


これらの式が評価されたときに何が起こるかを正確に理解するには、次のものが必要です。

  1. Hoogle、リストのモナドインスタンスを検索し、
  2. 2番目の式のより具体的なタイプ

これがモナドインスタンスです:

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)
于 2012-08-15T13:57:19.160 に答える