Haskell 一元型混淆

Haskell 一元型混淆,haskell,types,monads,parsec,Haskell,Types,Monads,Parsec,我正在经历。这是一个很棒的教程,但我遇到了一个: 使用以下命令重写parseNumber: 做记号 使用>>=运算符进行显式排序 我对do符号没有任何问题: parseNumber :: Parser LispVal parseNumber = do x <- many1 digit let y = read x return $ Number y 但我总是遇到类型错误。我有两个问题 为什么我会出现类型错误?我是不是误

我正在经历。这是一个很棒的教程,但我遇到了一个:

使用以下命令重写parseNumber:

  • 做记号
  • 使用>>=运算符进行显式排序
  • 我对do符号没有任何问题:

    parseNumber :: Parser LispVal
    parseNumber = do x <- many1 digit 
                     let y = read x
                     return $ Number y
    
    但我总是遇到类型错误。我有两个问题

  • 为什么我会出现类型错误?我是不是误解了一元绑定操作符
  • 为什么我的do表示法解决方案没有出现类似的类型错误

  • 我觉得我缺少了一个关于类型的基本概念?

    如果您正在尝试从do表示法到bind表示法的非平凡转换,我建议您以“平凡”的方式进行转换,然后使其自由指向

    回顾:

    x <- m === m >>= \x -> let x = e === let x = e in 现在,如果您想使用
    liftM
    ,您需要停止使用bind,因为提升函数需要一个一元值作为其参数

    parseNumber = liftM (Number . read) (many1 digit) parseNumber=liftM(Number.read)(多个1位)
    在您的情况下,bind具有以下类型:

    (>>=) :: Parser a -> (a -> Parser b) -> Parser b
    
    (因为您使用的是
    解析器
    作为Monad)

    您给bind两个参数:第一个参数,
    many1位
    ,应该是ok(关于类型);但是第二个参数的类型是
    liftM
    的结果类型,即
    Parser a->Parser b
    ,这不符合第二个参数的预期类型
    (a->Parser b)


    在没有测试它的情况下:不要使用
    liftM(Number.read)
    作为bind的第二个参数,而是尝试使用
    return。号码。阅读
    -这应该是正确的类型,可能会给出您想要的…

    非常好的答案。现在它变得更有意义了。 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 parseNumber = liftM (Number . read) (many1 digit)
    (>>=) :: Parser a -> (a -> Parser b) -> Parser b