Parsing 哈斯克尔:格雷厄姆·赫顿图书解析(Ch-8)“`parse(fv)out`做什么?它是如何做的?
我的问题是关于格雷厄姆·赫顿的书 第8.4节中创建了一个解析器,我假设任何回答的人都有这本书,或者可以在上面的链接中看到幻灯片8的链接 称为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
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