【问题标题】:Parsing a text to the tree in Racket/Scheme将文本解析到 Racket/Scheme 中的树
【发布时间】:2019-05-24 06:00:09
【问题描述】:

我正在尝试将我的 C++ 代码转换为 Racket,因为我正在学习 Racket。我的简化 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;
}

非常简单的代码。我对 Racket 的翻译是:

(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))))

如何解决?

【问题讨论】:

  • 抱歉解析树,我现在就修复它。
  • 没有办法让它成为纯函数式的?
  • 在这种情况下,我的意思是不可变变量。
  • 可以以纯粹的功能方式完成(见我的回答),你只需要保留一个堆栈来记住我们在解析中的位置。

标签: functional-programming scheme lisp racket


【解决方案1】:

您的原始方法的问题是您试图直接移植一个命令式解决方案,甚至使用传递引用来跟踪遍历状态。那是行不通的,第一步是以函数式编程风格重新考虑解决方案。

我们必须跟踪我们在嵌套结构中的位置的这类问题,使用 stack 数据结构可以更好地解决。我将使用 list 来实现列表堆栈,并使用以下帮助器在最顶部的列表中添加新元素:

(define (append-top ele stack)
  (cons (append (car stack) (list ele))
        (cdr stack)))

现在是实际的解决方案。假设输入列表格式正确,&lt;&gt; 的数量相同且顺序正确(不执行错误检查):

(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))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-25
    • 1970-01-01
    • 2012-10-24
    • 2018-11-10
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多