do块中的返回类型

时间:2013-12-19 19:41:56

标签: haskell types return monads

我正在尝试理解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”?不是没有“”?

3 个答案:

答案 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直觉。