【问题标题】:How to create a Scheme definition to parse a compound S-expression and put in a normal form如何创建 Scheme 定义以解析复合 S 表达式并放入正常形式
【发布时间】:2013-01-30 22:59:17
【问题描述】:

给定一个形式为:(* 3 (+ x y)) 的表达式,我如何评估该表达式以将其置于(+ (* 3 x) (* 3 y)) 的形式中? (注意:在一般情况下,3 是任何常数,“x”或“y”可以是单个变量或其他 s 表达式的项(例如 (+ 2 x))。

如何编写一个 lambda 表达式来递归地计算原始表达式中的项目(原子?)并确定它们是常量还是项?如果是术语,则需要再次递归评估以确定该术语列表中每个项目的类型。

再一次,对我来说,问题的症结在于定义的递归“内核”。

我显然需要一个基本情况来确定一旦我到达表达式最深处的最后一个单个原子。然后递归地“备份”工作,根据规则以适当的形式构建表达式。

来自 Java / C++ 背景,我很难理解如何在 Scheme 中从语法上做到这一点。

【问题讨论】:

    标签: scheme racket mit-scheme


    【解决方案1】:

    让我们从最初的问题快速绕开一些稍微相关的问题。假设你得到了以下内容:你想编写一个评估器,它接受像(* 3 "hello") 这样的“字符串构建”表达式并将其“评估”为“hellohellohello”。我们想做的其他例子包括

    (+ "rock" (+ (* 5 "p") "aper"))     ==> "rockpppppaper"
    (* 3 (+ "scis" "sors"))             ==> "scissorsscissorsscissors"
    

    要解决这样的问题,我们需要准确指定输入的形状。本质上,我们想要描述一种数据类型。我们会说我们的输入将是“字符串表达式”。让我们简称他们为str-exprs。那么让我们来定义一下str-expr的含义。

    str-expr 是:

    1. <string>
    2. (+ <str-expr> <str-expr>)
    3. (* <number> <str-expr>)

    通过这种表示法,我们试图说str-exprs 都适合这三种形状中的一种。

    一旦我们对数据的形状有了很好的了解,我们就有更好的指南来编写处理str-exprs 的函数:他们必须对这三个备选方案进行案例分析!

    ;; A str-expr is either:
    ;;      a plain string, or
    ;;     (+ str-expr str-expr), or
    ;;     (* number str-expr)
    
    ;; We want to write a definition to "evaluate" such string-expressions.
    
    ;; evaluate: str-expr -> string
    (define (evaluate expr)
      (cond
        [(string? expr)
         ...]
        [(eq? (first expr) '+)
         ...]
        [(eq? (first expr) '*)
         ...]))
    

    '...' 是我们将要填写的内容。

    实际上,我们知道如何填写更多关于 '...' 的内容:我们知道在第二种和第三种情况下,内部部分本身就是 str-exprs。这些是可能发生重复的主要地点:由于我们的数据是根据自身描述的,处理它们的程序也可能需要引用它们自己。简而言之,处理str-exprs 的程序几乎肯定会遵循这种形式:

    (define (evaluate expr)
      (cond
        [(string? expr)
         ... expr 
         ...]
        [(eq? (first expr) '+)
         ... (evaluate (second expr))
         ... (evaluate (third expr))
         ...]
        [(eq? (first expr) '*)
         ... (second expr) 
         ... (evaluate (third expr))
         ...]))
    

    这一切甚至都没有做任何实际工作:我们可以仅仅因为数据的形状告诉我们这部分,就可以计算出这部分。填写 '...' 的其余部分以使这一切顺利进行实际上并不算太糟糕,尤其是当我们还考虑我们已经编写的测试用例时。 (Code)

    正是这种标准的数据分析/案例分析是您问题的核心,它在 HTDP 等课程中广泛涵盖。这不是特定于 Scheme 或 Racket 的:您会在 Java 中进行相同类型的数据分析,并且您会在许多其他地方看到相同类型的方法。在 Java 中,用于案例分析的底层机制可能会有所不同,也许是动态调度,但核心思想都是一样的。您需要描述数据。一旦有了数据定义,就可以使用它来帮助您勾勒出处理该数据所需的代码。使用测试用例来确定如何填写草图。

    【讨论】:

    • 很好的解释。非常比你。
    【解决方案2】:

    你需要分解你的问题。我将从遵循 HtDP (www.htdp.org) 方法开始。你的输入是什么?你能准确地指定它们吗?在这种情况下,这些输入将是自引用的。

    然后,指定输出形式。实际上,您上面的文字对此有点模糊:我想我知道您的输出形式是什么样的,但我并不完全确定。

    接下来,编写一组测试。这些应该基于您输入术语的结构;从最简单的开始,然后从那里向上工作。

    一旦你有一套好的测试,实现这个功能应该很简单。如果您遇到困难,我很乐意提供帮助!

    【讨论】:

    • 很好的参考。我会检查一下。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-01
    相关资源
    最近更新 更多