Parsing 哈斯克尔:格雷厄姆·赫顿图书解析(Ch-8)“`parse(fv)out`做什么?它是如何做的?

Parsing 哈斯克尔:格雷厄姆·赫顿图书解析(Ch-8)“`parse(fv)out`做什么?它是如何做的?,parsing,haskell,monads,Parsing,Haskell,Monads,我的问题是关于格雷厄姆·赫顿的书 第8.4节中创建了一个解析器,我假设任何回答的人都有这本书,或者可以在上面的链接中看到幻灯片8的链接 称为item的基本解析器描述为: type Parser a = String -> [(a, String)] item :: Parser Char item = \inp -> case inp of [] -> [] (x:xs) -> [(x,xs)] 它与do一起用于定义另一个解析器p(d

我的问题是关于格雷厄姆·赫顿的书

第8.4节中创建了一个解析器,我假设任何回答的人都有这本书,或者可以在上面的链接中看到幻灯片8的链接

称为
item
的基本解析器描述为:

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

item :: Parser Char

item = \inp -> case inp of
        [] -> []
        (x:xs) -> [(x,xs)]
它与
do
一起用于定义另一个解析器
p
do
解析器)

返回
定义为:

return  :: a -> Parser a

return v = \inp -> [(v,inp)]
parse :: Parser a -> String -> [(a,String)]

parse p inp = p inp
parse
定义为:

return  :: a -> Parser a

return v = \inp -> [(v,inp)]
parse :: Parser a -> String -> [(a,String)]

parse p inp = p inp
程序(do解析器)获取一个字符串,并选择第一个和第三个字符,然后将它们以元组的形式返回,字符串的其余部分在一个列表中,例如,
“abcdef”
生成
[('a','c'),“def”]

我想知道这是怎么回事
(f v)out
在里面
[(v,out)]->解析(f v)out
返回一个解析器,然后将其应用于
out

  • do
    解析器中的
    f
    item
    并且
    item
    获取字符
    'c'
    返回
    [('c',[])]

  • 这怎么可能是一个解析器,它怎么能把
    作为一个参数取出来

也许我只是不明白
(fv)
的作用

  • 当再次调用
    时,
    解析器如何每次“删除”返回值以对输入字符串的其余部分进行操作

  • 通过
    do
    解析器工作的对象是什么,在每个步骤中是如何更改的,通过什么方式更改的


  • fv
    产生
    解析器b
    ,因为
    f
    a->Parser b
    类型的函数,
    v
    a
    类型的值。然后你调用
    parse
    ,使用
    Parser b
    和字符串
    out
    作为参数

    “do”解析器中的F是项

    不,不是。让我们考虑一个简化的(尽管现在有点无意义的)语法分析器版本:

    p = do x <- item
           return x
    
    因此
    >=
    的右操作数,即
    f
    ,是
    \x->返回x
    ,而不是

    此外,当再次调用项时,“do”解析器如何每次“删除”返回值以对输入字符串的其余部分进行操作?通过“do”解析器工作的对象是什么,它是如何改变的,每一步都是如何改变的,通过什么方式改变的

    应用解析器时,它返回一个元组,其中包含解析后的值和表示其余输入的字符串。例如,如果查看
    ,元组的第二个元素将是
    xs
    ,它是输入字符串的尾部(即,包含除第一个字符外的输入字符串的所有字符的字符串)。元组的第二部分将作为新的输入提供给后续解析器(根据
    [(v,out)]->parse(f v)out
    ),这样每个后续解析器将把前一个解析器生成的字符串作为其输出元组的第二部分(作为其输入的后缀)作为输入


    针对你的评论:

    当你写“p=item>=\x->return x”时,这是否等同于第一行“p=do x相关的建议是,不要惊慌(意思是,不要匆忙;或者,慢慢来),并遵循类型

    首先,
    Parser
    s

    type Parser a = String -> [(a,String)]
    
    是从
    String
    到类型
    a
    和剩余字符串的结果值配对列表的函数(因为
    type
    定义类型同义词,而不是像
    data
    newtype
    do这样的新类型)

    剩下的字符串将被用作下一个解析步骤的输入。这是这里的主要内容

    你是在问,是吗

    [(v,out)]->parse(f v)out中的
    (f v)
    如何返回一个解析器,然后将该解析器应用于
    out

    答案是,
    f
    的类型表示它是这样做的:

    (>>=) :: Parser a -> (a -> Parser b) -> Parser b    -- or, the equivalent
    (>>=) :: Parser a -> (a -> Parser b) -> (String -> [(b,String)])
    --       p              f                inp
    
    我们有
    f::a->Parser b
    ,所以它就是这样做的:应用于
    a
    类型的值,它返回
    Parser b
    类型的值

    f    :: a       -> (String  -> [(b,String)])      -- so that
    f (v :: a)      ::  String  -> [(b,String)]       -- and,
    f (v :: a) (out ::  String) :: [(b,String)]  
    
    p       :: String -> [(a,   String)]
    --         inp         v    out
          f ::             a -> String   -> [(b, String)]
    --                     v    out
    p >>= f :: String                    -> [(b, String)]     -- a combined Parser
    --         inp                            v2  out2
    
    因此,无论
    parse p inp
    产生的值是什么,都必须是
    f
    等待处理的值。类型必须“适合”:

    这也回答了你的第二个问题

    这怎么可能是一个解析器,它怎么能把
    作为一个参数取出来

    真正的问题是,是什么样的
    f
    做了这样的事情?它从哪里来?这是你的第四个问题

    答案是,
    do
    -符号中的示例

    p :: Parser (Char, Char)
    
    p = do x <- item
           _ <- item
           y <- item
           return (x,y)
    
    因为函数是嵌套的,所以最终的
    返回
    可以访问那里的
    y
    x
    ;而正是
    解析器
    绑定安排了输出剩余字符串作为下一个解析步骤的输入:

    p = item >>= f     -- :: String -> [((Char,Char), String)]
        where    
               { f x = item >>= f2
                        where { f2 _ = item >>= f3
                                        where { f3 y = return (x,y) }}}
    
    i、 e.(假设
    inp
    是长度为2或更长的字符串)

    parse p inp——假设'inp`'
    =(项目>>=f)inp——长度至少为2 NB。
    =
    让[(v,左)]=项目inp——通过>>的定义=
    在里面
    (f)左
    =
    设[(v,左)]=项目输入
    在里面
    设x=v——内联'f'的定义`
    在(项目>>=f2)左侧
    =
    设[(v,左)]=项目输入
    设x=v
    在let[(v2,left2)]=项left--中,再次使用>>=的定义
    在(F2V2)左2
    =
    ..........
    =
    
    让[(x,left1)]=item inp--x我在阅读语法时也遇到了类似的问题,因为这不是我们所习惯的

    (>>=) :: Parser a -> (a -> Parser b) -> Parser b
    
    p >>= f = \inp -> case parse p inp of
                           [] -> []
                           [(v,out)] -> parse (f v) out
    
    关于这个问题:

    我想知道
    (fv)out
    in
    [(v,out)]->如何解析(fv)
    
          p :: Parser a                     --   m  a
    f       ::        a -> Parser b         --      a -> m  b
    f <$> p :: Parser    ( Parser b )       --   m     ( m  b )
    f =<< p :: Parser             b         --   m          b
    
    p       :: String -> [(a,   String)]
    --         inp         v    out
          f ::             a -> String   -> [(b, String)]
    --                     v    out
    p >>= f :: String                    -> [(b, String)]     -- a combined Parser
    --         inp                            v2  out2
    
    p :: Parser (Char, Char)
    
    p = do x <- item
           _ <- item
           y <- item
           return (x,y)
    
    p = do { x <- item
           ; do { _ <- item
                ; do { y <- item
                     ; return (x,y) }}}
    
    p :: Parser (Char, Char) -- ~ String -> [((Char,Char), String)]
    
    p = item >>= (\ x ->              -- item :: Parser Char ~ String -> [(Char,String)] 
                   item >>= (\ _ ->                      -- x :: Char
                              item >>= (\ y ->           -- y :: Char
                                         return (x,y) )))
    
    p = item >>= f     -- :: String -> [((Char,Char), String)]
        where    
               { f x = item >>= f2
                        where { f2 _ = item >>= f3
                                        where { f3 y = return (x,y) }}}
    
    parse p inp                            -- assume that `inp`'s 
      = (item >>= f) inp                   --  length is at least 2     NB.
      =
        let  [(v, left)] = item inp        -- by the def of >>=
        in                                
            (f v) left
      =
        let  [(v, left)] = item inp
        in
           let  x = v                      -- inline the definition of `f`
           in  (item >>= f2) left
      =
        let  [(v, left)] = item inp
        in let  x = v 
           in let  [(v2, left2)] = item left     -- by the def of >>=, again
              in (f2 v2) left2
      =
        ..........
      =
        let  [(x,left1)] = item inp        -- x <- item
             [(_,left2)] = item left1      -- _ <- item
             [(y,left3)] = item left2      -- y <- item
        in 
            [((x,y), left3)]
      =
        let   (x:left1)  = inp             -- inline the definition
              (_:left2)  = left1           -- of `item`
              (y:left3)  = left2
        in 
            [((x,y), left3)]
      =
        let   (x:_:y:left3) = inp
        in 
            [((x,y), left3)]
    
    (>>=) :: Parser a -> (a -> Parser b) -> Parser b
    
    p >>= f = \inp -> case parse p inp of
                           [] -> []
                           [(v,out)] -> parse (f v) out