我正在经历Write Yourself a Scheme in Haskell。这是一个很棒的教程,但是我遇到了一个parsing exercises:
parseNumber :: Parser LispVal
parseNumber = liftM (Number . read) $ many1 digit
使用以下方法重写parseNumber:
我没有问号:
parseNumber :: Parser LispVal
parseNumber = do x <- many1 digit
let y = read x
return $ Number y
对于#2,我尝试了很多变体,例如:
parseNumber :: Parser LispVal
parseNumber = (many1 digit) >>= (liftM (Number . read))
但我一直遇到类型错误。我有两个问题。
我觉得我错过了关于类型的基本概念?
答案 0 :(得分:11)
你正在尝试从do-notation到绑定表示法的非平凡转换,我建议以“琐碎”的方式进行,然后使其成为无点。
回想:
x <- m === m >>= \x -> let x = e === let x = e in
然后你有:
parseNumber = many1 digit >>= \x -> let y = read x in return (Number y)
(我已删除$
以避免优先级问题。)
然后我们可以将其转换为:
parseNumber = many1 digit >>= \x -> return (Number (read x)) = many1 digit >>= return . Number . read
现在,如果你想使用liftM
,你需要停止使用bind,因为提升的函数需要一个monadic值作为参数。
parseNumber = liftM (Number . read) (many1 digit)
答案 1 :(得分:2)
在您的情况下,bind具有类型:
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
(因为你使用Parser
作为Monad)
你给bind两个参数:第一个,many1 digit
,应该没问题(关于类型);但是第二个参数的类型是liftM
的结果类型,即Parser a -> Parser b
,而不符合第二个参数的预期类型(a -> Parser b)
!
没有测试它:不是使用liftM (Number.read)
作为绑定的第二个参数,而是尝试使用return . Number . read
- 这应该是正确的类型并且可能提供你想要的...