为什么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 }
答案 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 a
与Int
匹配”) 。但为什么这在第一种情况下起作用呢?
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 a
(m = []
和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一起工作,但我仍然不确定你的目的是什么。