函数中的 do 符号不一致
Inconsistent do notation in functions
为什么允许这个功能:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
这不是:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
编译错误:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
我明白为什么功能 2 不能工作,但为什么功能 1 可以工作?
以及为什么这样做有效:
-- function 3
myfunc = do
x <- getLine
return (show x)
我明白了 returns IO String
那么,为什么函数 1 也没有被强制执行此操作?
在 function1 中,myfunc
中的 do
块在列表 monad 中工作,因为 String
实际上只是 [Char]
.在那里,return True
只是创建了 [True]
。当您执行 x <- return True
时,它会从 [True]
中“提取”True
并将其绑定到 x
。下一行 show x
将 True
转换为字符串 "True"
。这是编译器值期望看到的 return 值,最终工作正常。
同时在 function2 中,myfunc 中的 do
块也在列表 monad 上工作(出于同样的原因,String
实际上是 [Char]
) 但调用 getLine
仅在 IO
monad 中可用。毫不奇怪,这失败了。
-- 编辑 1
OP 添加了一个 function3
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
不,这不应该出于同样的原因 function2 失败。
-- 编辑 2
OP 已更新 function3 以修复复制粘贴错误。
-- function 3
myfunc = do
x <- getLine
return (show x)
评论中提到了这一点,但为了清楚起见,这是可行的,因为当未指定类型信息时,GHC 会做出最好的推断,在看到 getLine
后,它认为它是 IO String
确实提供 getLine
.
注意 - 我用尽可能随意的语气写了这个答案,没有错,目的是让初学者可以轻松理解它。
do
块在任意 Monad
的上下文中工作。在这种情况下,Monad
是 []
。列表的 Monad
实例基于列表理解:
instance Monad [] where
return x = [x]
xs >>= f = [y | x <- xs, y <- f x]
您可以这样对 do
符号进行脱糖处理:
myfunc :: String
myfunc = do
x <- (return True)
show x
-- ==>
myfunc = [y | x <- return True, y <- show x]
-- ==>
myfunc = [y | x <- [True], y <- show x]
在列表理解中,x <- [True]
实际上与 let x = True
相同,因为您只是从列表中绘制 一个 元素。所以
myfunc = [y | y <- show True]
当然,“y
在 show True
中的所有 y
的列表”只是 show True
。
为什么允许这个功能:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
这不是:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
编译错误:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
我明白为什么功能 2 不能工作,但为什么功能 1 可以工作?
以及为什么这样做有效:
-- function 3
myfunc = do
x <- getLine
return (show x)
我明白了 returns IO String
那么,为什么函数 1 也没有被强制执行此操作?
在 function1 中,myfunc
中的 do
块在列表 monad 中工作,因为 String
实际上只是 [Char]
.在那里,return True
只是创建了 [True]
。当您执行 x <- return True
时,它会从 [True]
中“提取”True
并将其绑定到 x
。下一行 show x
将 True
转换为字符串 "True"
。这是编译器值期望看到的 return 值,最终工作正常。
同时在 function2 中,myfunc 中的 do
块也在列表 monad 上工作(出于同样的原因,String
实际上是 [Char]
) 但调用 getLine
仅在 IO
monad 中可用。毫不奇怪,这失败了。
-- 编辑 1
OP 添加了一个 function3
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
不,这不应该出于同样的原因 function2 失败。
-- 编辑 2
OP 已更新 function3 以修复复制粘贴错误。
-- function 3
myfunc = do
x <- getLine
return (show x)
评论中提到了这一点,但为了清楚起见,这是可行的,因为当未指定类型信息时,GHC 会做出最好的推断,在看到 getLine
后,它认为它是 IO String
确实提供 getLine
.
注意 - 我用尽可能随意的语气写了这个答案,没有错,目的是让初学者可以轻松理解它。
do
块在任意 Monad
的上下文中工作。在这种情况下,Monad
是 []
。列表的 Monad
实例基于列表理解:
instance Monad [] where
return x = [x]
xs >>= f = [y | x <- xs, y <- f x]
您可以这样对 do
符号进行脱糖处理:
myfunc :: String
myfunc = do
x <- (return True)
show x
-- ==>
myfunc = [y | x <- return True, y <- show x]
-- ==>
myfunc = [y | x <- [True], y <- show x]
在列表理解中,x <- [True]
实际上与 let x = True
相同,因为您只是从列表中绘制 一个 元素。所以
myfunc = [y | y <- show True]
当然,“y
在 show True
中的所有 y
的列表”只是 show True
。