绑定/赋值运算符适用于返回String的函数,但不适用于返回Int的函数

时间:2012-11-11 14:05:42

标签: haskell ghc ghci

为什么Prog A编译运行正常,而Prog B无法编译?感谢

Prog A

func :: String -> String
func a = a

mydofn a = do 
  x <- func a
  return x

main = print "Finished"

Prog B

func :: Int -> Int
func a = a

mydofn a = do 
  x <- func a
  return x

main = print "Finished"

Prog B编译错误:

Couldn't match expected type `m0 t0' with actual type `Int'
In the return type of a call of `func'
In a stmt of a 'do' block: x <- func a
In the expression:
  do { x <- func a;
       return x }

2 个答案:

答案 0 :(得分:6)

使用do-notation,此代码:

mydofn a = do 
  x <- func a
  return x

只是

的语法糖
mydofn a = func a >>= (\x -> return x)

现在,>>=的类型为Monad m => m a -> (a -> m b) -> m b,但在第二个示例中,应用func a的类型为Int,无法与Monad m => m a统一(因为Int是独立的,而不在某些m内),这就是类型检查器告诉您的内容(“无法将m aInt匹配”) 。但为什么这在第一种情况下起作用呢?

Haskell中的字符串只是字符列表([Char])。并且a Monad instance for [a] in the standard library看起来像这样:

instance  Monad []  where
    m >>= k             = foldr ((++) . k) [] m
    return x            = [x]

因此[Char]Monad m => m am = []a = Char)统一,您的第一个示例变为

mydofn a = foldr ((++) . (\x -> [x])) [] (func a)

或等效

mydofn a = concat . map (\x -> [x]) $ func a

这只是将字符串的每个字符映射到单个字符串("abc"映射到["a", "b", "c"]),然后将所有结果字符串连接在一起(["a", "b", "c"]变为"abc"

答案 1 :(得分:4)

在prog A中,您正在使用列表monad,因为String = [Char]。 没有Int monad! 在prog A中,

mydofn a = do 
  x <- func a
  return x

相当于

mydofn a = [x | x <- func a]

所以它实际上只是遍历列表的元素,而不是改变任何东西。

在编程A中,m0 t0[] Char匹配,您无法将Int写为m0 t0,这就是为什么您收到了编程B的错误。


mydofn相当于

mydofn a = do 
  func a

相当于mydofn a = func a,与mydofn a = a相同。

我认为这是一个减少的例子,目的是澄清问题。你还想用mydofn做什么?

也许你的意思

mydofn a = do 
  x <- return (func a)
  return x

可以让它与Int一起工作,但我仍然不确定你的目的是什么。