Parsing 如何根据输出上消耗的数据量使此解析代码变为惰性?
有人知道如何使代码变得懒惰和不严格,从而在解析输入数据时生成AST树吗?当前使用的列表输入是从左到右读取的,但构造方式是相反的。正因为如此,我不得不在两个地方使用“反向”Parsing 如何根据输出上消耗的数据量使此解析代码变为惰性?,parsing,haskell,Parsing,Haskell,有人知道如何使代码变得懒惰和不严格,从而在解析输入数据时生成AST树吗?当前使用的列表输入是从左到右读取的,但构造方式是相反的。正因为如此,我不得不在两个地方使用“反向” type Program = [Instruction] data Instruction = Next | Prev | Plus | Minus | Print | Loop [Instruction] deriving Show parse :: String -> Program parse ys = reve
type Program = [Instruction]
data Instruction = Next | Prev | Plus | Minus | Print | Loop [Instruction] deriving Show
parse :: String -> Program
parse ys = reverse exps where
(exps, _) = parse' ys []
parse' [] is = (is, [])
parse' (x:xs) is = case x of
'>' -> parse' xs (Next:is)
'<' -> parse' xs (Prev:is)
'+' -> parse' xs (Plus:is)
'-' -> parse' xs (Minus:is)
'.' -> parse' xs (Print:is)
'[' -> parse' after $ Loop (reverse inside):is where (inside, after) = parse' xs []
']' -> (is, xs)
_ -> parse' xs is
类型程序=[指令]
数据指令=下一个|上一个|加|减|打印|循环[指令]导出显示
解析::字符串->程序
parse ys=反向表达式,其中
(exps,u)=解析'ys[]
解析“[]is=(is,[]))
parse'(x:xs)is=
'>'->parse'xs(下一步:is)
“parse”xs(加:is)
'-'->parse'xs(减:is)
'.->parse'xs(打印:is)
$Loop后面的'['->parse'(内部反转):是where(内部,后面)=parse'xs[]
']'->(is,xs)
_->parse'xs是
如果您希望它是惰性的,那么您的函数需要返回如下所示的值:
instr1 : instr2 : ... : <thunk>
我不知道您是否有意这么做,但带有额外参数的辅助parse'
函数(在其中累积结果)正是您用来提高严格语言性能的模式(如果它支持尾部调用消除)。尾部递归实际上是这里的敌人
带有累加器的尾部递归函数几乎必然是非惰性的,因为只有在触及基本情况并决定如何处理最终累加器值时,才能知道输出的第一个“片段”。因此,要求输出的使用者必须在处理整个输入时等待,并且必须在内存中缓冲整个输出
惰性递归代码最明显的方法是让函数返回应用于某些字段的数据构造函数(在本例中为:
),其中递归调用存储在一个(或多个)字段中。这允许使用者在要求递归调用的输出之前检查构造函数和您生成的任何其他字段
这也意味着,如果您正在编写一个递归函数来生成一个递归数据类型,并且希望它是惰性的,那么您通常会在返回类型的结构之后构造您的函数——这正是递归使用者通常反映其输入类型结构的方式。原型列表制作者需要一个返回代码< > [][COD]和一个返回<代码>的情况:“RealsivCeCule .< /P>一个旁注,您可以通过缩略语来缩写这些情况,并且将更好的方式放在<<代码> < <代码>结尾>代码>解析< <代码>中,而不是在中间的情况下。如果不使用这些值,它们无论如何也不会被计算,但这将防止该行从屏幕边缘移动。
parse [] = []
parse (x:xs) = instr : parse xs
where instr = ...