【问题标题】:Scheme, When to use Symbols instead of Strings?方案,何时使用符号而不是字符串?
【发布时间】:2011-03-08 17:21:06
【问题描述】:

我为我的原始英语提前道歉;我会尽力避免语法错误等。

两周前,我决定更新我对 Scheme(及其启示)的知识,同时实施一些我手头得到的数学材料,特别是我参加的自动机理论和计算课程中的常规语言。

到目前为止,我一直将字母表表示为符号列表而不是

  1. 字符列表,因为我想要可变大小的字母。
  2. 字符串列表,因为我觉得有点不雅。

我缺乏经验,想知道您对这个特定选择的看法。符号是为某种特定类型的任务保留的,因此我是否在滥用它们?非常感谢对此的任何评论,因为我正在寻求指导。

在更远的范围内,还有时间在一个无限的字母表上实现所有可能单词的集合。我正在考虑通过允许的最大单词大小来限制集合。再说一次,这是一个好习惯还是我应该转而选择流?我觉得流会是一种更好的方法,但我还没有学会它们,所以我真的不知道使用它们的含义。

无论如何,欢迎任何建议或评论。我非常感谢您花时间阅读我的疑问。周末愉快!

【问题讨论】:

标签: scheme stream regular-language


【解决方案1】:

简单的区别是符号的比较非常便宜。可以使用eq? 来比较两个符号是否相同。这是因为在编译期间,编译器本质上会用数字枚举所有符号,所以您只是在比较整数,这是一种非常便宜的机器操作。

这意味着两个符号是相同的当且仅当它们由相同的字符组成。无法辨别代码中具有相同字符的两个符号,它们是常量,它们是相同的对象,就像33

然而,两个字符串很可能是驻留在不同内存位置的不同对象,要比较它们需要分别比较每个字符以进行匹配。

因此,符号应该并且经常用于此目的,例如,考虑到:

(assq 'symb  '((foo 1 2 3) (bar symb) (symb "match")))

这将返回列表(symb "match") 这与比较一样便宜:

(assq 4  '((0 1 2 3) (1 symb) (4 "match")))

返回列表(4 "match")。但是,当使用字符串作为键时,assq 不再足够,它使用eq? 过程进行比较,而必须使用assoc,它使用equal? 过程,因为它递归比较,所以成本要高得多结构体。上面的实现实际上足够便宜,经常被用作在解释器中建模关联数组和环境的一种方式,即使它肯定不是随机访问。

编辑:正如你所问,在流上:

Scheme 标准支持一个不错的对,一个是称为force 的函数,另一个是称为delay特殊形式。实际上是什么

(delay (+ 1 2 3))

或任何其他代替(+ 1 2 3)返回的代码是所谓的“承诺”,它延迟了该承诺中答案的计算,但承诺与6我们评估时结果将相同到达那里。这可能看起来没什么用,但是说结果取决于一些可以更改的变量:

(define x 4) ; x is bound to 4.
(let ((promise (delay (+ 2 x)))) ; evaluating the expression now would result into 6, but we delay it.
  (set! x 5) ; we change the value of x.
  (display (force promise)) ; displays 7
  (set! x 6) ; change it again
  (force promise) ; ALSO displays 7, not 8
)

很明显,promise 确实只被评估了一次,当再次强制执行时,它会产生与第一次评估时相同的值。

这通常用于流或概念上的“无限列表”。在这种情况下,列表的 cdr 是对列表其余部分的承诺,它在检索时被强制执行,否则它将变成非终止计算,例如,通常我们定义:

(define (stream-cdr x) (force (cdr x))) ; it forces that promise to evaluate it.
; and optionally
(define stream-car car) ; same

由于这个不能评估它的论点,它需要是一种特殊的形式:

(define-syntax stream-cons
  (syntax-rules ()
    ((stream-cons x y)
     (cons x (delay y))))

您的 Scheme 编译器或解释器现在会将每次出现的 (stream-cons x y) 转换为任意 x 和 y 的 (cons x (delay y))

所以,作为一个简单的例子,既然我们的评估被延迟到我们需要它,我们可以创建一个无限的零列表:

(define zero-stream (stream-cons 0 zero-streams))

一个由自身组成的列表,如果我们没有使用流,它肯定永远不会终止,没用,但它显示了这个想法。我们可以一遍又一遍地使用stream-cdr,而不会到达一个空列表,我们只是再次得到相同的“无限0列表”。

一个更实际的例子是所有斐波那契数字的列表,它有点复杂:

(define fibs 
  (stream-cons 0 (stream-cons 1
    (stream-map + fibs (stream-cdr fibs))))

Stream-map 是法线贴图的类似物,它的定义相当复杂,但我相信你可以查一下,它会自己生成一个流。所以 `(stream-map (lambda (x y) (+ 1 x y)) zeroes zeroes) 将生成一个完全充满一个的流。 fibs 流本身是递归定义的。前两个元素是给定的,其余的是从恰好是 fibs 的两个流和 fibs 本身的 stream-cdr 计算出来的。

【讨论】:

  • 干杯!您对使用符号的含义进行了非常简单和简洁的解释。完全理解你所说的一切,不费吹灰之力:)我会坚持下去。顺便说一句,因为我觉得这个帖子不会吸引更多的答案,你有没有关于流的空话或者对像我这样的新手的任何其他评论或建议?无论哪种方式,再次感谢您花时间回答。非常感谢。
  • 精彩的展览!非常感谢:)
猜你喜欢
  • 2013-05-13
  • 1970-01-01
  • 1970-01-01
  • 2014-09-28
  • 2020-07-31
  • 2018-09-15
  • 1970-01-01
  • 2012-10-01
  • 2011-06-25
相关资源
最近更新 更多