我正在尝试理解Haskell中的Monads,在我无数次使用代码进行实验时遇到过这样的事情:
f2 = do
return "da"
并且它不想编译有关类型的巨大错误。我认为唯一重要的部分是:
No instance for (Monad m0) arising from a use of return'
The type variable `m0' is ambiguous
然后我将代码更改为:
f2 = do
return "da" :: IO [Char]
它运作得非常好。但是当我试图弄乱一点并将类型更改为IO Int时再次出现错误。那么为什么这种类型实际上不是“含糊不清”? 此外,当我在返回之前添加一些东西时:
f2 = do
putStrLn "das"
return 2
然后我不必指定返回的类型。 那么有人可以解释我到底发生了什么吗?另外为什么在第一种情况下返回输出“da”?不是没有“”?
答案 0 :(得分:8)
首先让我们指出
do
return a
与
完全相同return a
现在,问题是return
的类型为
return :: Monad m => a -> m a
当你有一个像
这样的宣言时foo = bar
其中foo
没有参数haskell使其“单态”。结果是Haskell无法猜测m
是什么,并且不会对其进行概括,因此您需要一个显式类型签名。最一般的是
f2 :: Monad m => m String
f2 = return "das"
但你也可以使用IO
或任何其他monad
f2 :: IO String
最后,在您的上一个示例中,由于您要返回2
,因此您必须提供一个类型签名,表明您正在返回某种数字,例如
f2 :: IO Integer
答案 1 :(得分:5)
这是众所周知的Monomorphism_restriction
使用签名
f2 :: Monad m => m String
f2 = do
return "da"
或使用语言扩展程序:
{-# LANGUAGE NoMonomorphismRestriction #-}
f2 = do
return "da"
获取有效代码
答案 2 :(得分:3)
在了解monad时,自己手动展开它们很有帮助,例如简单的例子:
test0 :: IO String
test0 = do
a <- getLine
putStrLn a
return a
如果我们启用语言扩展{-# LANGUAGE ScopedTypeVariables #-}
,那么我们可以使用它的显式类型来注释monad中的每一行,它将显示返回块的类型。
{-# LANGUAGE ScopedTypeVariables #-}
test1 :: IO String
test1 = do
a <- getLine :: IO String
putStrLn a :: IO ()
return a :: IO String
我们还可以注释左侧模式匹配的显式类型,它从右侧的monad上下文中“提取”。
test2 :: IO String
test2 = do
(a :: String) <- getLine :: IO String
(() :: ()) <- putStrLn a :: IO ()
return a :: IO String
我们甚至可以将说明扩展到其组成部分:
test3 :: IO String
test3 = getLine >>=
(\a -> putStrLn a >>=
\() -> return a)
希望有助于建立你的monad直觉。