【问题标题】:Evaluating cons expressions using "eval" and "map" (Racket interpreter written in Racket)使用“eval”和“map”评估 cons 表达式(用 Racket 编写的 Racket 解释器)
【发布时间】:2018-10-18 00:30:59
【问题描述】:

我的任务是使用 Racket 语言本身为我在一系列 5 个实验中的一个课程编写一个 Racket 解释器,第一个涉及编写两个基本函数:lookupevaluatelookup 函数有一个列表作为我们的环境,包含一个符号表和一个符号。您肯定会注意到,就第一个作业而言,该表是非常基本的。我已经编写并测试了这个函数,一切都很好。

但是,evaluate 函数让我陷入了困境。它确实正确地评估了我给它的原始过程:例如,'(+ 3 4 (- 5 2) 3) 确实评估为13。它也适用于单数cons 表达式,例如'(cons 1 null) = '(1)'(cons 2 4) = '(2 . 5)。但是,每当我尝试评估 multiple cons 表达式的复合语句时,它都会引发错误。我一直在研究的一个特殊案例是'(cons 1 (cons 2 null))。经过多次调试,我发现问题如下:

  1. Map 计算最终表达式 '(2 null) 正确'(2)。但是后来……
  2. 等待上述 Map 过程完成的 Map,不知何故最终评估为 '(1 (2))。我希望它评估为'(1 '(2)),这本来可以,但它没有,而且我不完全理解为什么。但最终,结果...
  3. 过程 cons 与 Map 返回的列表相结合,产生 '(cons 1 (2))
  4. 程序试图eval这个字符串,但是却对我大喊大叫,因为它没有将(2) 识别为一个列表,而是期望它是一个过程。
#lang racket
(provide lookup)
(provide evaluate)

(define-namespace-anchor mySpace)
(define ns (namespace-anchor->namespace mySpace))

;The list which serves as the environment for our lookup function.
(define testEnvironment(list
                        (cons 'x 10)
                        (cons '+ +)
                        (cons '- -)
                        (cons '* *)
                        (cons 'y 20)
                        (cons 'cons cons)
                        (cons 'nil '())))
;Assumes that there is at least one element in the environment given for consideration.
(define lookup
  (lambda (symbol environment)
    (if(symbol? symbol)
       (let recursiveLookup((symbol symbol) (environment environment))
         (if(equal? symbol (car (car environment)))
            (cdr (car environment))
            (if(null? (cdr environment))
               (error "This symbol does not exist in the provided environment!")
               (recursiveLookup symbol (cdr environment)))))                 
       (error "The provided argument is not a symbol."))))

(define evaluate
  (lambda (expression environment)
    (if(not (pair? expression))
       (cond         
         ;If the expression is a number, then return that number.
         ((number? expression) expression)
         ;If the expression is null, or contains a symbol equivalent to null, return null
         ((null? expression) null)
         ((equal? null (lookup expression environment)) 'null)
         ;Otherwise, the expression must be some kind of symbol, so look up 
         ; the value of that symbol.
         (else (lookup expression environment)))
       ;If the expression is a list, then use map to evaluate the remaining elements
       ;in the expression. Then pair the first element (which is a procedure)
       ;to the resulting list. Finally, apply the procedure to the resulting function
       ;using evaluate to obtain the final value.
       (eval (cons (lookup (car expression) environment) 
                   (map (lambda (listElement) 
                          (evaluate listElement environment)) 
                        (cdr expression)))
             ns))))

更好地了解这里发生的事情以及如何解决它对我来说非常重要,因为如果我不能处理这么多,我无法想象编写这个 Racket 解释器的其余部分会在一个不稳定的基础上变得容易。我花了大约 15 个小时试图以多种方式解决这个问题,但我碰壁了……我担心我在想这个问题,但即便如此还是非常令人沮丧,因为这些程序似乎完美无缺在任何不涉及多个cons 表达式的情况下。这让我感到很悲伤和懵懂的熊猫。

我希望我对你们所有人的问题表达得足够好,并且我向所有花时间在这里帮助我的人表示我永远的感激之情!谢谢大家的存在,因为我太胆小了,不敢向现实世界中的任何人寻求帮助:3

【问题讨论】:

    标签: racket eval interpreter map-function cons


    【解决方案1】:

    您不应使用eval。使用apply

    (let ((exprs (map (lambda (listElement) (evaluate listElement environment)) expression))
      (apply (car exprs) (cdr exprs)))
    

    eval 评估所有参数。对于他们自己评估的数字,但它会尝试用数字评估列表,并且它不是有效的方案代码。您的参数已经被评估,因此apply 与 eval 执行相同的操作,只是它按原样使用传递的参数。稍后您可能需要制作自己的版本以支持用户定义的过程。

    我认为评估操作数而不是假设它是一个符号是很好的。例如。这应该工作:

    ((car (cons + '())) 4 5)
    ; ==> 9
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-13
      • 1970-01-01
      • 2018-05-23
      • 1970-01-01
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      相关资源
      最近更新 更多