我刚刚开始使用monad,我无法弄清楚为什么这两个表达式的评估方式不同:
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")
Run Code Online (Sandbox Code Playgroud)
Phy*_*hyx 10
类型不同,因此行为不同是合理的
第一个表达式将被视为 Num t => [(t, Char)]
在[>> =)中使用[]作为monad意味着它推断出monad应该是List monad并且在List Monad http://en.wikibooks.org/wiki/Haskell/Understanding_monads/List的上下文中(>> =)是concatMap,返回是(:[]).
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
Run Code Online (Sandbox Code Playgroud)
是相同的
concatMap (\n -> concatMap (\ch -> [(n, ch)]) ['a', 'b']) [1,2]
Run Code Online (Sandbox Code Playgroud)
返回 [(1,'a'),(1,'b'),(2,'a'),(2,'b')]
在你的第二个例子中,真正发生的是什么
表达式的类型更通用:
Prelude> :t return ([1,2],['a','b'])
return ([1,2],['a','b']) :: (Monad m, Num t) => m ([t], [Char])
Run Code Online (Sandbox Code Playgroud)
因为你在GHCi中运行它会发生一些事情.GHCi可以被认为是一个非常大的特殊IO Monad.因此,由于没有指定monad,当GHC尝试打印结果时,mMonad将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])
Run Code Online (Sandbox Code Playgroud)
因此,它们具有不同的价值.
也许你的单子的存在混淆里面的参数return.但是,看看它的类型:
ghci> :t return
return :: Monad m => a -> m a
Run Code Online (Sandbox Code Playgroud)
return 对它的参数一无所知 - 它只需要一个值,任何值,并将它放在一个默认的monadic上下文中.
要准确了解评估这些表达式时会发生什么,您需要:
这是 monad实例:
instance Monad [] where
m >>= k = foldr ((++) . k) [] m
m >> k = foldr ((++) . (\ _ -> k)) [] m
return x = [x]
fail _ = []
Run Code Online (Sandbox Code Playgroud)
(我们可以忽略>>和fail,因为我们没有使用它们.)
那么让我们扩展我们的表达:
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch)
Run Code Online (Sandbox Code Playgroud)
所以设置m = [1, 2],k = \n -> ['a','b'] >>= \ch -> return (n,ch)我们得到:
foldr ((++) . (\n -> ['a','b'] >>= \ch -> return (n,ch))) [] [1,2]
Run Code Online (Sandbox Code Playgroud)
现在要摆脱第二个>>=,m = ['a', 'b']并且k = \ch -> return (n, ch):
foldr ((++) . (\n -> rest)) [] [1,2]
where
rest = foldr ((++) . (\ch -> return (n,ch))) [] ['a', 'b']
Run Code Online (Sandbox Code Playgroud)
并且return很容易摆脱:
foldr ((++) . (\n -> rest)) [] [1,2]
where
rest = foldr ((++) . (\ch -> [(n,ch)]) [] ['a', 'b']
Run Code Online (Sandbox Code Playgroud)
另一方面,第二个表达式的值:
return ([1,2],['a','b'])
Run Code Online (Sandbox Code Playgroud)
取决于你所在的monad.在monad列表中,它简单地变为:
[([1,2], ['a','b'])] :: [] ([Int], String)
Run Code Online (Sandbox Code Playgroud)
而在Maybe monad中,它是:
Just ([1,2], ['a', 'b']) :: Maybe ([Int], String)
Run Code Online (Sandbox Code Playgroud)