Haskell中do表达式里<-的用法疑问:两段代码为何一可行一报错
问题解析:Haskell Do语句中
let与<-的核心差异 两段代码的核心矛盾出在y <- fmap f g x这一行,本质是没搞清楚<-操作符的使用规则,具体拆解如下:
<-的硬性要求
在do语句块里,var <- expr的作用是从Monad上下文中提取值,这意味着expr的类型必须是Monad m => m a(比如IO String、Maybe Int这类带上下文的类型)。你当前的do块基于IO Monad(第一行getLine是IO String),所以<-右边必须是IO类型的表达式。fmap f g x的类型本质fmap f g是把函数f映射到g这个Functor实例上(如果g是函数,那fmap f g等价于f . g),传入参数x后得到的是一个纯值(比如Integer、Maybe String这类,不带IO上下文),完全不符合<-要求的IO类型,自然编译报错。第一段代码正常运行的原因
第一段里的let y = fmap f g x是纯绑定逻辑,只是给右边的表达式结果起个名字,不需要考虑Monad上下文——不管右边是纯值还是其他Functor类型,let都能正常工作。最后用return y把y包装成IO类型,和整个do块的IO上下文匹配,所以可以正常运行。
举个具体例子:假设f = (+1),g = Just,那么fmap f g x就是Just (x+1)(Maybe Integer类型),用let y = ...绑定完全没问题;但如果用y <- ...,Haskell会期望右边是IO Integer,类型不匹配直接触发错误。
内容的提问来源于stack exchange,提问作者Piskator
相关产品推荐
相关产品推荐

