如何使用>>=重写《Write Yourself A Scheme》中的parseNumber函数
正确实现
直接对应do语法脱糖的>>=版本
do表达式本质是Monad操作的语法糖,你给出的do块脱糖后直接对应以下代码:
parseNumber :: Parser LispVal parseNumber = many1 digit >>= \x -> return $ Number (read x)
脱糖规则说明:
- 形如
a <- action; rest的do语句,会被转换为action >>= \a -> rest - 你原来的do块只有两步,刚好对应一次>>=绑定操作:
- 第一步
many1 digit的类型是Parser String,作为>>=的左操作数 - 右操作数是接收String类型参数x的lambda,内部把x转成Integer再包成Number构造器,最后用return抬到Parser Monad中,类型刚好匹配
Parser LispVal
- 第一步
简化版本
利用Monad和Functor的性质,还可以进一步简化为更简洁的写法,效果完全等价:
-- <$>是fmap的中缀写法 parseNumber :: Parser LispVal parseNumber = Number . read <$> many1 digit
原理是m >>= return . f等价于fmap f m,这里f就是Number . read,可以省略显式的lambda和return操作。
常见类型错误原因
你之前遇到类型不匹配,大概率是以下两种情况:
- 忘记在lambda最后加return:如果直接写
many1 digit >>= \x -> Number (read x),右操作数返回的是LispVal类型,不是Parser LispVal,就会类型报错 - 搞错了>>=两侧的类型匹配关系:>>=左操作数是
Parser a,右操作数必须是a -> Parser b,两边的a类型要对应上
内容的提问来源于stack exchange,提问作者TookieWookie
相关产品推荐
相关产品推荐

