首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Haskell: Graham Hutton Book-(old-黄色),解析(Ch-8)

Haskell: Graham Hutton Book-(old-黄色),解析(Ch-8)
EN

Stack Overflow用户
提问于 2018-03-10 16:35:32
回答 3查看 85关注 0票数 1

我完全按照书(第一版)中的样子复制了这个例子。

书中给出了:

代码语言:javascript
运行
复制
p :: Parser (Char,Char)

p =  do x <- item
        item
        y <- item
        return (x,y)

在x上编译错误,为什么?

|

代码语言:javascript
运行
复制
40 | p =  do x <- item
   |         ^^^^^^^^^

:40:9: error:
    * Couldn't match type `([(Char, String)], [(Char, String)])'
                     with `[((Char, Char), String)]'
      Expected type: Parser (Char, Char)
        Actual type: String -> ([(Char, String)], [(Char, String)])
    * In a stmt of a 'do' block: x <- item
      In the expression:
        do x <- item
           item
           y <- item
           return (x, y)
      In an equation for `p':
          p = do x <- item
                 item
                 y <- item
                 ....
(deferred type error)
EN

回答 3

Stack Overflow用户

发布于 2018-03-11 02:36:28

你是正确的。解析器只是一个函数的别名,所以它使用(->)的Monad实例。这就是为什么你得到的是String -> ([(Char, String)], [(Char, String)])而不是Parser (Char, Char)String -> [((Char, Char), String)]

我建议您自己创建一个新类型,并实例化Functor、Applicative和Monad以获得预期的结果。

这将完成以下工作:

代码语言:javascript
运行
复制
newtype Parser a = Parser { parse :: String -> [(a, String)] }

item :: Parser Char
item = Parser $ \case
  [] -> []
  (c:cs) -> [(c, cs)]

instance Functor Parser where
  fmap f p = Parser $ \s ->
    concatMap (\(a, s) -> [(f a, s)]) $ parse p s

instance Applicative Parser where
  pure a = Parser $ \s -> [(a, s)]
  pf <*> pa = Parser $ \s ->
    concatMap
      (\(f, s') -> fmap (\(a, s'') -> (f a, s'')) (parse pa s'))
      (parse pf s)

instance Monad Parser where
  return a = Parser $ \s -> [(a, s)]
  pa >>= f = Parser $ \s ->
    concatMap (\(a, s') -> parse (f a) s') (parse pa s)

p :: Parser (Char,Char)
p =  do x <- item
        item
        y <- item
        return (x,y)
票数 1
EN

Stack Overflow用户

发布于 2018-03-10 22:25:38

你有type Parser a = String -> [(a,String)]

因此,您使用的是(->) String Monad实例。因此,xy的类型都是[(Char, String)]。您的代码想要return类型为([(Char,String)],[(Char,String)])(x,y)对。因此,你得到了p :: String -> ([(Char,String)],[(Char,String)]),但是你声称p :: Parser (Char, Char)p :: String -> [(Char, Char)]是一样的。这两个值不匹配,因此会出现类型错误。

你的问题是你把Parser当做一个单体来对待,但它不是。

代码语言:javascript
运行
复制
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
return :: a -> Parser a

但是你有:

代码语言:javascript
运行
复制
(>>=) :: Parser a -> ([(a,String)] -> Parser b) -> Parser b
return :: [(a,String)] -> Parser a

或者更一般地说:

代码语言:javascript
运行
复制
(>>=) :: (String -> a) -> (a -> String -> b) -> (String -> b)
return :: a -> (String -> a)
票数 0
EN

Stack Overflow用户

发布于 2018-03-10 22:54:25

看起来您还没有为类型Parser定义monad实例。您可以尝试这样做,或者只使用包含书中定义的library for parsing

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49207052

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档