[英]Parsing a text to the tree in Racket/Scheme
因为我正在学习球拍,所以我试图将我的C ++代码转换为球拍。 我的简化C ++代码是:
struct Node
{
char value = '\0';
std::vector<Node> kids;
explicit Node(char ch) : value(ch) {}
};
void ParseTree(const std::string& tokens, size_t& i, Node& root)
{
while (i < tokens.size())
{
const Token& token = tokens[i++];
if (token == '<') // children begin
{
ParseTree(tokens, i, root.kids.back());
}
else if (token == '>') // children end, go up
{
return;
}
else
{
root.kids.emplace_back(token);
}
}
}
Node ParseTree(const std::string& s)
{
size_t i = 0;
Node root('$');
ParseTree(Parse(s), i, root);
return root;
}
如此简单的代码。 我对球拍的翻译是:
(define (parse-tree tokens)
(if(empty? tokens)
'()
(cond
[(eq? '< (car tokens))
(list (parse-tree (cdr tokens)))]
[(eq? '> (car tokens))
(parse-tree (cdr tokens))] ; no return, how to step up?
[else
(cons (car tokens)(parse-tree (cdr tokens)))])))
这里的问题是我没有返回(eq?'>(汽车令牌),所以新节点被添加到底部。一个小测试:
(parse-tree '(1 < 2 < 3 4 > > Z < X >))
应该:
'(1 (2 (3 4)) Z (X))
它是:
'(1 (2 (3 4 Z (X))))
如何解决?
原始方法的问题在于,您试图直接移植一个命令式解决方案,甚至使用按引用传递来跟踪遍历状态。 那将行不通,第一步是以功能编程的方式重新考虑解决方案。
使用堆栈数据结构可以更好地解决此类问题(必须跟踪嵌套结构内部的位置)。 我将使用列表来实现列表堆栈,并使用以下帮助程序将新元素追加到最上面的列表中:
(define (append-top ele stack)
(cons (append (car stack) (list ele))
(cdr stack)))
现在为实际解决方案。 假设输入列表的格式正确,且<
和>
数目相同且顺序正确(不执行错误检查):
(define (parse-tree tokens)
(let parse ([tokens tokens] [stack '(())])
(cond [(null? tokens)
; solution is at the top of the stack, return it
(car stack)]
[(eq? (car tokens) '<)
; start new sublist at the top of the stack
(parse (cdr tokens) (cons '() stack))]
[(eq? (car tokens) '>)
; pop top element of the stack, append it to previous
; frame, continue with solution where we left it
(parse (cdr tokens) (append-top (car stack) (cdr stack)))]
[else
; add current element to top of stack
(parse (cdr tokens) (append-top (car tokens) stack))])))
它按预期工作!
(parse-tree '(1 < 2 < 3 4 > > Z < X >))
=> '(1 (2 (3 4)) Z (X))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.