dan*_*lei 3 ruby parsing haskell
对于一个赋值,我们必须实现像一个非常基本的sexp解析器,这样的输入,如:
"((a b) ((c d) e) f)"
Run Code Online (Sandbox Code Playgroud)
它将返回:
[["a", "b"], [["c", "d"], "e"], "f"]
Run Code Online (Sandbox Code Playgroud)
由于这是一个更大的赋值的一部分,解析器只给出有效的输入(匹配的parens和c).我在Ruby中提出了以下解决方案:
def parse s, start, stop
tokens = s.scan(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}|\w+/)
stack = [[]]
tokens.each do |tok|
case tok
when start
stack << []
when stop
stack[-2] << stack.pop
else
stack[-1] << tok
end
end
return stack[-1][-1]
end
Run Code Online (Sandbox Code Playgroud)
这可能不是最好的解决方案,但它可以完成这项工作.
现在,我对一个惯用的Haskell解决方案的核心功能感兴趣(即我不关心lexing或选择分隔符,考虑已经lexed输入会很好),如果可能只使用"核心"haskell,没有扩展或者像parsec这样的库.
请注意,这不是赋值的一部分,我只是对Haskell的处理方式感兴趣.
[["a", "b"], [["c", "d"], "e"], "f"]
Run Code Online (Sandbox Code Playgroud)
haskell中没有有效类型(因为列表中的所有元素都必须在haskell中具有相同的类型),因此您需要为嵌套列表定义自己的数据结构,如下所示:
data NestedList = Value String | Nesting [NestedList]
Run Code Online (Sandbox Code Playgroud)
现在,如果您有一个令牌列表,其中Token被定义为data Token = LPar | RPar | Symbol String
,您可以将其解析为NestedList,如下所示:
parse = fst . parse'
parse' (LPar : tokens) =
let (inner, rest) = parse' tokens
(next, outer) = parse' rest
in
(Nesting inner : next, outer)
parse' (RPar : tokens) = ([], tokens)
parse' ((Symbol str) : tokens) =
let (next, outer) = parse' tokens in
(Value str : next, outer)
parse' [] = ([],[])
Run Code Online (Sandbox Code Playgroud)