而且,它如何从内存池中分配内存?符号,数字以及它如何处理类型转换的字节数,因为它没有转换的int和float类型
我真的尝试过在互联网上进行研究,对不起,我不得不问这里因为我一无所获。
答案 0 :(得分:3)
这个问题的答案取决于实现。
以下是在Scheme编译器研讨会中完成的工作方式。 编译器为32位Sparc机器生成机器代码。
请参阅http://www.cs.indiana.edu/eip/compile/back.html
Data Formats
All of our data are represented by 32-bit words, with the lower three bits as a kind of type-tag. While this would normally only allow us eight types, we cheat a little bit: Booleans, empty-lists and characters can be represented in (much) less than 32 bits, so we steal a few of their data bits for an ``extended'' type tag.
Numbers:
--------------------------------------
| 29-bit 2's complement integer 000 |
--------------------------------------
Booleans:
------------------- -------------------
#t: | ... 1 00000 001 | #f: | ... 0 00000 001 |
------------------- -------------------
Empty lists:
-----------------
| ... 00001 001 |
-----------------
Characters:
---------------------------------------
| ... 8-bit character data 00010 001 |
---------------------------------------
Pairs, strings, symbols, vectors and closures maintain a 3-bit type tag, but devote the rest of their 32 bits to an address into the heap where the actual value is stored:
Pairs:
--------------- -------------
| address 010 | --> | car | cdr |
-----\--------- / -------------
-----------
Strings:
--------------- -------------------------------------------------
| address 011 | --> | length | string data (may span many words)... |
-----\--------- / -------------------------------------------------
-----------
Symbols:
--------------- --------------------------
| address 100 | --> | symbol name (a string) |
-----\--------- / --------------------------
-----------
Vectors:
---------------
| address 101 |
-----|---------
v
-----------------------------------------------------------
| length | (v-ref 0) | (v-ref 1) | ... | (v-ref length-1) |
-----------------------------------------------------------
Closures:
---------------
| address 110 |
-----|---------
v
-----------------------------------------------------------------------
| length | code pointer | (free 0) | (free 1) | ... | (free length-1) |
-----------------------------------------------------------------------
答案 1 :(得分:3)
与其他动态类型语言一样,Scheme也有类型,但它们与值相关联,而不是与变量相关联。这意味着您可以在一个点为变量分配一个布尔值,在另一个时间点为一个数字分配一个布尔值。
Scheme不使用C类型,因为Scheme实现根本不必与C绑定:几个编译器发出本机代码,而不通过C.并且像其他答案一样提到,Scheme(和它之前的Lisp)试图让程序员不必处理这些(通常)不重要的细节作为目标机器的寄存器大小。
在Lisp变体中,数字类型特别复杂。 Scheme有所谓的numeric tower,它抽象出代表性的细节。很像很多"更新"诸如Go,Python和Ruby之类的语言,Scheme将在机器寄存器或内存中的单词中表示小整数(称为" fixnums")。这意味着它在C中会很快,但是一旦整数超过该大小,它就会自动切换到不同的表示,这样就可以表示任意大数字而无需任何特殊配置。
其他答案已经向您展示了一些方案的实施细节。我最近在博客上发表了关于CHICKEN Scheme's internal data representation的文章。该帖子包含指向其他几个Scheme的数据表示的链接,最后您将在Python,Ruby,Perl和旧的Lisp变体中找到对数据表示的进一步引用。
Lisp和Scheme的美妙之处在于它们是如此古老的语言,但它们仍然包含着新的想法和#34;现在才被添加到其他语言。垃圾收集几乎必须发明才能使Lisp工作,它支持数字塔很长一段时间,在很早的时候就添加了面向对象,匿名程序从一开始就在那里我认为,当作者proved表示lambda可以像goto
一样有效地实现时,Scheme引入了闭包。
所有这些都是在20世纪50年代到80年代之间发明的。与此同时,甚至在垃圾收集被主流接受之前花了很长时间(基本上用Java,大约45年),并且对封闭/匿名程序的普遍支持仅在过去5年左右变得流行。甚至尾调用优化也没有在大多数语言中实现; JavaScript程序员现在才发现它。有多少"现代"语言仍然需要程序员使用一组单独的运算符处理任意大整数并作为特殊类型?
请注意,很多这些想法(包括您询问的数字类型转换)会带来额外的开销,但是通过巧妙的实现技术可以减少开销。最终大多数都是净胜利,因为它们可以提高程序员的工作效率。如果您在代码的选定部分需要C或汇编性能,大多数实现允许您通过各种技巧下拉到金属,因此这不是关闭给您的。缺点是它没有标准化(尽管 cffi用于Common Lisp),但就像我说的那样,Scheme并不与C绑定所以它会如果规范在非C实现上强制执行C外部函数接口,则会非常粗鲁。
答案 2 :(得分:2)
简短的回答是它具有原始数据类型,但作为程序员,您不必担心它。
Lisp的设计者来自数学背景,并没有在特定平台中使用限制作为灵感。在数学中,数字不是32位,但我们确实区分了不精确的数字。
Scheme最初在MacLisp中解释,并继承了MacLisp的类型和原语。 MacLisp基于Lisp 1.5。
变量没有类型,大多数实现都有机器指针作为数据类型。通过将最后一个有效位作为类型标志进行操作,将字符,符号和小整数等原语存储在地址中,由于机器将内存中的对象与寄存器宽度对齐,因此对于实际对象始终为零。
如果添加两个大于结果大小的整数,则为不同类型。在C中它会溢出。
;; This is Common Lisp, but the same happens in Scheme
(type-of 1) ; ==> BIT
(type-of 10) ; ==> (INTEGER 0 281474976710655)
(type-of 10000000000000000) ; ==> (INTEGER (281474976710655))
即使我们对待它们,对象的类型也是不同的。前两个不使用除指针之外的任何额外空间,但最后一个是指向堆上分配的实际对象的指针。
所有这些都取决于实现。 Scheme标准没有规定它是如何完成的,但许多人就是这样做的。你can read the standard并没有说明如何建模数字,只说明行为。您可以制作一个R6RS Scheme,将所有内容存储在字节数组中。