方案,何时使用符号而不是字符串?
我提前为我的英语水平表示歉意;我会尽力避免语法错误等。
两周前,我决定更新我对Scheme(及其启示)的知识,同时实现我手上得到的一些数学材料,特别是我注册的自动机理论和计算课程中的常规语言。
到目前为止,我一直将字母表表示为符号列表而不是
- 字符列表,因为我想要具有可变大小的字母。
- 字符串列表,因为我有点觉得那不优雅。
我缺乏经验,想知道您对这个特定选择的看法。符号是为某种特定类型的任务保留的吗?我是否滥用了它们?对此的任何评论都非常感谢,因为我正在寻求指导。
更进一步,还有时间在字母表上实现所有可能单词的集合,这是无限的。我正在考虑通过允许的最大字数来限制集合。再说一次,这是一个很好的做法还是我应该去流媒体?我觉得流将是一种更好的方法,但我还没有学习它们,所以我真的不知道使用它们的含义。
无论如何,欢迎任何建议或评论。我真的很感谢您花时间阅读我的疑虑。祝你周末愉快!
I apologize in advance for my primitive english; i will try my best to avoid grammatical errors and such.
Two weeks ago i decided to freshen my knowledge of Scheme (and its enlightnings) whilst implementing some math material i got between hands, specifically, Regular Languages from a course on Automata theory and Computation in which i am enrolled.
So far, i've been representing alphabets as lists of symbols instead of
- lists of chars because i want to have letters of variable size.
- lists of strings because i somewhat feel thats unelegant.
I'm inexperienced and would like to know your opinion on this particular choice. Are symbols reserved for some particular kind of task and by this am i misusing them? Any comment on this is very appreciated for i'm seeking guidance.
On a further reach, there will be also the time to implement the set of all possible words over an alphabet, which is infinite. I was thinking to limit the set by the maximum size of words permitted. Again, is this a good practice or should i instead go for the streams? I feel that streams would be a better approach but i haven't learned them yet so i don't really know the implications are of using them.
Anyhow, any suggestion or commentary is welcomed. I really appreciate the time you took to read my doubts. Have a nice weekend!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简单的区别在于符号的比较成本非常低。可以使用
eq?
来比较两个符号是否相同。这是因为在编译时,编译器本质上会用数字枚举所有符号,因此您只是比较整数,这是一种非常便宜的机器操作。这意味着两个符号是相同的当且仅当它们由相同的字符组成。无法辨别代码中具有相同字符的两个符号,它们是常量,它们是相同的对象,就像
3
和3
一样。然而,两个字符串很可能是驻留在内存不同位置的不同对象,并且要比较它们需要分别比较每个字符是否匹配。
因此符号应该并且经常用于此目的,例如,考虑:
这返回列表
(symb "match")
这与比较一样便宜:它返回列表
(4 "匹配”)
。但是,当使用字符串作为键时,assq
不再足够,它使用eq?
过程进行比较,而必须使用assoc
,它使用equal?
过程,由于它递归地比较结构,所以成本要高得多。上面的实现实际上足够便宜,可以经常用作在解释器中对关联数组和环境进行建模的方法,即使它肯定不是随机访问。编辑:正如您所问,在流上:
Scheme 标准支持一对很好的函数,一个是名为
force
的函数,另一个是名为的特殊形式延迟。实际上
,或任何其他代码代替
(+ 1 2 3)
返回的是所谓的“承诺”,它延迟了该承诺中答案的计算,但承诺结果将是当评估到我们到达的6
时是相同的。这可能看起来毫无用处,但假设结果取决于某个可以更改的变量:很明显,承诺确实只评估一次,并且当再次强制时,它会产生与第一次评估时相同的值。
这是流或概念性“无限列表”中通常使用的内容。在这种情况下,列表的 cdr 是对列表其余部分的承诺,在检索列表时强制执行,否则它将变成一个不间断的计算,例如,通常我们定义:
因为这个无法评估其参数,它需要是一种特殊的形式:
您的Scheme编译器或解释器现在会将每次出现的
(stream-cons xy)
转换为(cons x (delay y))
任意任意的 x 和 y。因此,作为一个简单的例子,现在我们的评估被延迟到我们需要它为止,我们可以创建一个无限的零列表:
一个由自身组成的列表,如果我们没有使用流,它肯定永远不会终止,无用的,但它展示了这个想法。我们可以一遍又一遍地使用
stream-cdr
,而不会到达空列表,我们只是再次得到相同的“无限 0 列表”。一个更实际的例子是所有斐波那契数的列表,这有点复杂:
Stream-map 是法线贴图的类似物,它的定义非常复杂,但我相信你可以查找它,它会生成流本身。因此 `(stream-map (lambda (xy) (+ 1 xy)) Zeroes Zeroes) 将生成一个完全充满 1 的流。 fibs 流本身是递归定义的。前两个元素是给定的,其余元素是根据两个流计算的,这两个流恰好是 fibs 和 fibs 本身的流 cdr。
The simple difference is that symbols are extremely cheap to compare. One can use
eq?
to compare two symbols as identical. This is because during compile time, the compiler will essentially enumerate all symbols with a number, so you're just comparing integers, a very cheap machine operation.This means that two symbols are identical if and only if they are composed from the same characters. There is no way to discern two symbols that have the same characters in code, they are constants, they are the same objects, just as
3
and3
.Two strings however can very well be different objects residing in different locations of memory, and to compare them requires comparing every character separately for a match.
So symbols should, and are often used for this, for instance, considering:
This returns the list
(symb "match")
this is as cheap as comparing:Which returns the list
(4 "match")
. However, when using strings as keysassq
no longer suffices, which uses theeq?
procedure for comparison, ratherassoc
must be used, which uses theequal?
procedure, which is a lot more costly since it recursively compares structure. The above implementation is actually cheap enough to often be used as a way to model associative arrays and environments in interpreters, even though it's certainly not random access.Edit: As you asked, on streams:
The Scheme standard supports a nice pair, one is a function called
force
, the other though, is a special form calleddelay
. Effectively whatOr any other code in lieu of
(+ 1 2 3)
returns is a so-called 'promise', it delays the computation of the answer in that promise, but promises that the result will be identical when evaluated to that6
we get there. This might seem quite useless, but say the result depends on some variable, which can be changed:It becomes apparent that the promise is indeed evaluated only once, and when forced again, it yields the same value as when evaluated the first time.
This is what is typically used in streams, or conceptual 'infinite lists'. The cdr of the list in this case is a promise for the rest of the list which is forced when it's retrieved, as else it would turn into a nonterminating computation, for instance, commonly we define:
As this one can't evaluate its argument, it needs to be a special form:
Your Scheme compiler or interpreter will now translate every occurence of
(stream-cons x y)
to(cons x (delay y))
for any arbitrary x and y.So, as a simple example, now that our evaluation is delayed until we need it, we can create an infinite list of zeros:
A list consed up to itself, which would surely never terminate if we hadn't used a stream, useless, but it shows the idea. We can just use
stream-cdr
over and over again on this without ever either reaching an empty list, we just get the same 'infinite list of 0's' back again.A more practical example would be the list of all fibonacci numbers, which is some-what more complex:
Stream-map is the analogue of the normal map, it's definition is quite complex but I'm sure you can look it up, it generates a stream itself. So `(stream-map (lambda (x y) (+ 1 x y)) zeroes zeroes) would generate a stream completely filled with one's. The fibs stream is recursively defined in itself. The first two elements are given and the rest is computed from two streams which just happen to be fibs and the stream-cdr of fibs itself.