[英]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.