用ghci打印时return "abc"
的类型是什么?
问题的关键在于它在monad中是多态的:
ghci> :t return "abc"
return "abc" :: (Monad m) => m [Char]
打印的内容取决于选择哪个monad:
ghci> return "abc" :: Maybe String
Just "abc"
ghci> return "abc" :: [] String
["abc"]
但这是实际打印的内容:
ghci> return "abc"
"abc"
答案 0 :(得分:7)
当您在GHCi中键入表达式expr
时,会发生以下情况:
expr
的类型为t
; GHC尝试将t
与IO a
匹配。it <- expr
的内容,如果a
是Show
的实例而不是()
,则会执行print it
t
本身就是Show
的实例,则GHCi执行类似let it = expr
然后print it
的操作。基本上,你需要一种方法在GHCi提示符下运行IO动作并获取它们返回的值,以及玩纯值并查看你得到的值。这就是为什么GHCi的行为方式:如果看起来你正在使用IO动作,GHCi会这样做,然后如果该动作有一个可以显示并且有趣的结果(即不是()
)然后它会向您显示结果。如果它无法向您显示结果,那么这没什么大不了的,因为您可能只想运行IO操作;如果你想要结果,你可以用<-
命名它。另一方面,如果您的表达式似乎是不一个IO动作,GHCi会计算它并向您显示,如果无法显示,那么GHCi无法做任何有用的事情(这次没有副作用,所以抱怨。
在这种情况下,return "abc"
类型检查IO String
和String
是Show
的实例,因此GHCi执行类似
it <- return "abc"
print it
由monad定律与正好相同
print "abc"
因此结果。
答案 1 :(得分:4)
Haskell有一套令人困惑的规则来决定涉及数字的表达式类型;你可以看到Report section on ambiguous types and default instances。所以一般问题的答案很复杂。但是在GHCi中,如果您输入表达式 e ,您可以依赖这些规则来应用:
如果表达式 e 可以为某些类型IO T
键入T
,并且T
有Show
个实例,GHCi将运行计算并打印类型T
的结果值。这就是你的第三个例子中发生的事情。
如果无法在IO
monad中输入 e *表达式,则默认实例规则将起作用,GHCi将根据这些规则选择类型规则。如果类型具有Show
实例,GHCi将打印show
e 。这就是前两个示例中的情况:Maybe String
和[String]
是带有Show
个实例的纯值。
如果 e 的类型不有Show
个实例,那么GHCi会抱怨。如果您键入flip take
等表达式,则会发生这种情况。