1

为什么 Prog A 编译并运行良好,而 Prog B 编译失败?谢谢

前卫A

func :: String -> String
func a = a

mydofn a = do 
  x <- func a
  return x

main = print "Finished"

编B

func :: Int -> Int
func a = a

mydofn a = do 
  x <- func a
  return x

main = print "Finished"

程序 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 }
4

2 回答 2

6

使用 do-notation,此代码:

mydofn a = do 
  x <- func a
  return x

只是语法糖

mydofn a = func a >>= (\x -> return x)

现在,>>=有 type Monad m => m a -> (a -> m b) -> m b,但在你的第二个例子中,应用程序func a有 type Int,它不能被统一Monad m => m a(因为Int它自己而不是 some ),这就是类型检查器告诉你的m(“不能匹配”)。但为什么这在第一种情况下有效?m aInt

Haskell 中的字符串只是字符列表([Char])。标准库中有一个如下所示的Monad实例[a]

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

因此与(with and )[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")。

于 2012-11-11T14:20:38.943 回答
4

在 prog A 中,您使用的是 list monad,因为String = [Char]. 没有 Int 单子!在编 A 中,

mydofn a = do 
  x <- func a
  return x

相当于

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

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

在 prog A, m0 t0matches 中[] Char,您不能这样写Intm0 t0这就是您在 prog B 中遇到错误的原因。


mydofn相当于_

mydofn a = do 
  func a

which 等价于mydofn a = func awhich 表示与 相同mydofn a = a

为了澄清问题,我认为这是一个精简的例子。你还想做什么mydofn

也许你的意思是

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

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

于 2012-11-11T14:15:44.560 回答