【问题标题】:Scheme what are symbols good for and evaluate them计划什么是符号的好处并评估它们
【发布时间】:2012-10-29 05:28:37
【问题描述】:

我对方案很陌生,对引号和符号不太确定。

这是我的理解:

'a
-> a

'()
->(list)

'(1 2 3)
(list 1 2 3)

'(1 . 2)
(cons 1 2)

''a
(quote a)

So:

'(1 . 'a)
(1 quote a) => (list 1 quote a)

我想要实现的是以下。

((let ((x 1) (y 2)) 
  (lambda(f) ,f)) 'x)
-> 1

我向函数发送一个符号,该符号应被评估为当前范围,在这种情况下将返回 1。

相反,我有这个错误:

*** ERROR IN #<procedure #4>, (console)@243.32 -- Unbound variable: unquote

就好像 unquote 只能在 quote 内部使用。

编辑

我只是在阅读一些文档并找到了函数:“eval”,它似乎可以满足我的需求。

(define a 'foobar)
(define foobar 2)
(eval a)
-> 2

(define a 'x)
(define f (let ((x 1) (y 2)) 
 (lambda (h) (eval h))))
(f a)
*** ERROR -- Unbound variable: y
(f y)
*** ERROR IN (console)@278.4 -- Unbound variable: y

但我不确定是否真的明白。

这是鸡肉中的堆栈跟踪

Error: unbound variable: x

    Call history:

    <syntax>      (f (quote x))
    <syntax>      (quote x)
    <syntax>      (##core#quote x)
    <eval>    (f (quote x))
    <eval>    (eval h)  <--

编辑2

Eval 是邪恶的,但我想知道它是如何工作的非常重要。

所以在阅读了 Ankur 的答案后,我很确定这是范围的问题,实际上是这样。因此,据我了解,eval 似乎正在尝试使用“全局变量”来评估任何内容。

> (define a 11)
> (define b 'a)
> (eval b)
11
> (let ((a 10)) (eval b))
11
> (let* ((a 10) (b 'a)) (eval b))
11
> (let* ((a 10) (b 'a)) b)       
a
> (let* ((c 10) (d 'c)) d)
c
> (let* ((c 10) (d 'c)) (eval d))
*** ERROR -- Unbound variable: c

方案中的评估显然是邪恶的!

【问题讨论】:

  • 如果您的问题的答案是eval,那么您几乎总是做错事。如果您是 Scheme 的新手,那么这种可能性高达 100%。
  • @itsbruce 出于这个原因,了解它的工作原理更为重要。并不是说我会使用它,但我并不总是阅读我自己编写的代码。

标签: scheme symbols


【解决方案1】:
It's as if unquote was only available from within quote itself.

是的,您只能在带引号的表达式中取消引用,因为只有取消引用才有意义,即您正在引用表达式(不想评估表达式中的项目)但希望表达式的特定部分是评估,在这种情况下你使用 unquote。

(define a 10)
`(a b ,a) ==> '(a b 10)

在最后一个表达式中,我希望 a 和 b 不被计算,但第三个元素,即 a 应该被计算并替换为它的值,因此我们使用 unquote。

您的代码:

(define f (let ((x 1) (y 2)) 
 (lambda (h) (eval h))))

f 的参数必须是未计算的表达式,因为参数 h 是使用 eval 计算的。

因此您需要使用(f 'a)

注意:(f 'y) 将不起作用,因为使用 let 创建的 y 范围已消失。

【讨论】:

  • 我猜这个问题与eval有关。我更新了我的问题。显然 eval 正在使用全局范围的变量。即使您在不同的范围内使用它,它也可能不会尝试使用它们。我可能对范围在方案中的工作方式有误。
  • 另外,我不确定拥有 `(a b ,a) 有什么意义。我理解它给出的结果。它将给出一个带有 b 和 10 的列表。也就是说,既然 a 和 b 在这里没有被评估,我怎么能在不使用 eval 的情况下使用它。
【解决方案2】:

特别是对于这种情况,您不需要引用要评估的表达式,这将起作用:

(let ((x 1) (y 2)) 
  ((lambda (f) f) x))

=> 1

在问题的代码中,请注意变量x 仅存在于定义它的let 的范围内;最外面的 'x 符号将只是那个符号,与 let 表达式中的 x 无关:

((let ((x 1) (y 2)) 
   (lambda (f) f)) 'x)

=> 'x

【讨论】:

  • 我更新了我的问题。感谢您的快速答复。我使用 eval 进行了更新。因为 x 和 y 应该只能在 let 中使用。我认为使用 eval 实际上应该从 let 中进行 eval 并找到有界 x 或 y。
  • 嗯,你到底需要什么?在我看来,您正在尝试将方形钉安装在圆孔中,可能有一种更简单的方法可以在没有那么复杂的情况下实现您所需要的。哦,还有eval() is evil
  • 我只是在学习计划。一种用途是访问存储在关联列表中的函数。或哈希表。但我的猜测是,在哈希表中只存储符号或实际文本会更快。我将在 10 天内进行 80 分钟的讲座,并试图找到足够的话题来谈论。
  • 好吧,您不需要动态评估符号并在表达式中替换它的值。只需使用一个变量,就像我回答中的第一个 sn-p 一样 - 保持简单!
猜你喜欢
  • 2012-02-02
  • 2016-06-20
  • 2011-10-08
  • 2017-01-19
  • 2013-12-20
  • 2017-02-14
  • 1970-01-01
相关资源
最近更新 更多