Functional programming 什么是情商?mit模式解释器中的谓词do?

Functional programming 什么是情商?mit模式解释器中的谓词do?,functional-programming,scheme,lisp,Functional Programming,Scheme,Lisp,我知道(eq?obj1 obj2)仅当obj1和obj2引用内存中的同一对象时才会返回#t 1) (eq?2.6 2.6)返回#f,因为它们是浮点数,浮点数的表示形式在方案中不同。有人能解释一下它们在记忆中是如何表现的吗 2) 为什么成对和非空字符串经常返回#f,即使我们以前没有声明它们?例如:(eq?(cons12)(cons12)),当将相同的数字与eq?进行比较时,给出与equal?谓词相同的结果 例如,(define x 3)(define y 3)(eq?x y)返回#t 我还理解(e

我知道
(eq?obj1 obj2)
仅当obj1和obj2引用内存中的同一对象时才会返回
#t

1)
(eq?2.6 2.6)
返回
#f
,因为它们是浮点数,浮点数的表示形式在方案中不同。有人能解释一下它们在记忆中是如何表现的吗

2) 为什么成对和非空字符串经常返回
#f
,即使我们以前没有声明它们?例如:
(eq?(cons12)(cons12))
,当将相同的数字与
eq?
进行比较时,给出与
equal?
谓词相同的结果

例如,
(define x 3)(define y 3)(eq?x y)
返回
#t


我还理解
(eq?“()”())
返回
#t
,因为内存中只有一个空列表的表示形式,它是指向0的指针。

要理解这一点,您确实需要了解Lisp通常如何表示对象。下面的内容并不是麻省理工学院计划的具体内容,甚至可能不适用于该计划(或任何具体的实施),但其目的是让您了解一般的考虑事项。除了下面绘制的表示法之外,还有其他可能的表示法,但它们都有类似的折衷

对象表示 首先,系统需要了解关于任何对象的两件事:

  • 它是什么样的东西——它的类型
  • 它的值是什么——表示对象的一些位模式
当然,位的模式只有在类型的上下文中才有意义

有很多类型,在许多Lisp方言中,你可以创建新的类型,所以说“只能有这六种类型”是行不通的。但有些类型比其他类型更重要(我想说的是“某些类型比其他类型更相等”):例如,您可能希望小整数非常有效

在大多数情况下,最终会得到某种指向对象实际数据的指针。但现在有一个聪明的技巧可以做到:大多数(所有?)现代机器都是字节寻址的——内存地址的粒度为8位。但是,如果您只想指向较大的对象,那么指针中就有多余的位。因此,如果您在64位计算机上,并且只想指向64位边界上的对象,那么指针的低位3位永远不会被使用,如果您只想指向128位边界,则有4个备用位

因此,你可以做一个诡计:在一个64位的单词中,你可以打包一个指针,在指针底部不需要的几位中,打包一个标记,它可以编码几个最重要的类型

你甚至可以做得更好:对于一些小对象,你可以在指针指向的地方打包对象本身。典型的例子是小整数——Lisp在历史上称之为fixnums的东西。用你的话来说,你现在有了一个标签位的模式,上面写着“这是一个fixnum”,而fixnum的实际位,向右移动,为标签腾出空间。(实际上,“偶数fixnum”和“奇数fixnum”通常有两个标记,这两个标记允许您使用一个狡猾的技巧将fixnum变大一点,这一点我将留给您去解决)。Lisps传统上也会对
NIL
/
()
执行此操作,这可能是一个特殊的“NIL”标记,单词的其余部分为零。我不确定这对这个计划来说可能没什么意义

但一般来说,你不能这样做:大多数对象都必须用指针存储,在最一般的情况下,单词中的标记位会说“it's something”,指针会指向某个对象,该对象既有对象的类型,也有对象的值,并且有几个单词长

像小整数一样立即存储的对象通常称为“未装箱”,而基于指针的一般对象称为“已装箱”

eq?
做什么 那么,
eq?
做什么?简单:它告诉您这两个单词是否是相同的位模式:如果标记和指针/立即数值都是相同的位。这是非常快的(一条指令),但也非常原始

对于直接类型(如fixnums),它将告诉您这两个对象是否具有相同的值。对于指针类型,它将告诉您两个对象是否相同:如果两个指针指向相同的地址(并且具有相同的标记位,尽管如果没有,这将非常奇怪)。它不会告诉您两个指针类型是否表示相同的值,即使它们是不同的指针

实习:技巧 对装箱类型可以做的一个技巧是对它们进行实习:每次你准备制作一个新的装箱类型时,你都要看看之前是否制作了一个等价的装箱类型,如果已经制作了,你只需返回一个指向同一对象的指针。这意味着
eq?
对于任何两个等效的内部对象都将返回true,因为它们实际上是同一个对象。只有当对象的数量相对较少时,如果对象是不可变的或实际上是不可变的,或者如果您有意想要这种实习行为,那么实习对象才真正有意义

浮点数 浮点数为32位或64位。因此,在64位系统上,可以立即表示32位单浮点:在字的一半有一些标记位和一堆零,在另一半有浮点位。但你永远不能为双浮动做这件事。即使对于单个浮动,您也需要一个特殊的“浮动”标记,而标记是一种极其稀缺的资源——可能只有8个。(当然,大多数Lisp在living memory之前都是32位的,32位Lisp甚至不能立即存储一个浮点。)

因此,一般来说,单浮点数和双浮点数都是装箱的。实习浮动是没有意义的,因为你可以
(define (x f)
  (let ([g f])
    (eq? g f)))
(x 1.0)
> (eq? 1 1)
#t
> (eq? (expt 2 20) (expt 2 20))
#t
> (eq? (expt 2 64) (expt 2 64))
#f
> (eq? (expt 2 62) (expt 2 62))
#f
> (eq? (expt 2 61) (expt 2 61))
#t
> (eq? (- (expt 2 62) 1) (- (expt 2 62) 1))
#t