首页 文章

怎么样?在Racket工作?

提问于
浏览
7

在我的大学,我们不得不与Racket合作,因为我很喜欢它,我从No Starch购买了最近出版的书“Realm Of Racket” .

到目前为止它很棒,但是,当他们试图解释eq时,我无法弄清楚它们在第4章中的含义是什么?作品:

  • 首先,他们解释了如何平等?比较两个值是否由相同的部分组成 . 好的,没问题,我明白了:平等?与Java的equals(someObject)方法完全相同 . 如果两个对象/结构/任何内容相同,则返回#t .

  • 然后,我想,eq?必须等同于Java的==运算符,它不会按内容进行比较,而是基于引用 .

  • 这个想法似乎得到了书中以下句子的证实:"eq? compares whether changing one structure changes the other structure..."太棒了!让我们将它与下面的Java代码进行比较:

Point p1 = new Point(5, 5);
Point p2 = p1;
System.out.println(p1 == p2);   // true, since the reference has been copied.
System.out.println(p1.x);       // 5
System.out.println(p2.x);       // 5
p1.x = 42;
System.out.println(p1.x);       // 42
System.out.println(p2.x);       // Accordingly, 42

让我们在Racket中尝试一下:

(define cons1 (cons 1 empty))
(define cons2 cons1)
(eq? cons1 cons2)           ;; #t, since the refernce has been copied.
(set! cons1 (cons 2 empty))
cons1                       ;; Returns '(2) - as expected.
cons2                       ;; Still returns '(1).

为什么? cons2指向cons1,它本身指向'(2) . 另外,他们不是只是说一改变另一个就等于他们是平等的吗?

显然,现在我没有按照预期行事,因此,我看不到什么样的情况?是在做 . 也许我错了,它与引用没有任何关系......

如果有人知道这一点,请分享你的智慧;)

3 回答

  • 2

    有关 eq? 如何工作的技术解释,请查看当前的specification,您在该主题上获得了't find a more detailed reference. Or simply check Racket' s documentation,特别是程序 eq?eqv?equal? . 关于你的问题 - 结果与Scheme代码中的预期和正确一样,让我们看看为什么 . 请注意,在Java中的这一行:

    p1.x = 42;
    

    您正在修改 p1p2 指向的同一对象 . 而在这一行:

    (set! cons1 (cons 2 empty))
    

    您正在创建一个新的不同对象并将 cons1 设置为指向它,但 cons2 仍然指向旧对象 . 您可以在上一行之后确认这一点,比较 (eq? cons1 cons2) 将返回 #f .

    关键是:这些例子并不等同 . Java示例处理由两个不同引用指向的单个对象,而Scheme示例处理两个对象和两个引用 .

    为了进行比较,这里是一个与Java代码类似的Scheme示例,并按预期工作,因为在这里我们正在修改一个由两个引用指向的可变对象:

    #lang racket
    (require scheme/mpair) ;; `m` stands for "mutable"
    
    (define p1 (mlist 5 5))
    (define p2 p1)
    
    (eq? p1 p2)       ;; #t
    (mcar p1)         ;;  5
    (mcar p2)         ;;  5
    
    (set-mcar! p1 42)
    (eq? p1 p2)       ;; #t
    (mcar p1)         ;; 42
    (mcar p2)         ;; 42
    
  • 7

    啊:你想确保你改变结构 . 在您的示例中,它实际上不是更改现有值的结构,而是构造一个全新的值并将 cons1 指向它 . 你有这个概念: eq? 几乎是Java的 == .

    只是为了类比,这里是Java形式的错误,所以你看到出了什么问题:

    int[] lst1 = new int[] { 1 };       // (define cons1 (cons 1 empty))
    int[] lst2 = lst1;                  // (define cons2 cons1)
    System.out.println(lst1 == lst2);   // (eq? cons1 cons2)
    lst1 = new int[] { 2 };             // (set! cons1 (cons 2 empty))
    System.out.println(lst1[0]);        // (list-ref cons1 0)
    System.out.println(lst2[0]);        // (list-ref cons2 0)
    

    事实上,在这一点上,你需要检查 eq? -ness在这结尾:你会看到两个不再是 eq? :它们是两个不同的值 .

    你真正想要的是在结构上做 mutation ,而不是变量重新绑定 . 在Racket中,由于列表是不可变的,因此您需要使用允许变异的不同数据结构 . 向量是可以演示的一个示例数据类型 . 让我们再次"Rosetta"这样你可以看到这样的比喻:

    (define vec1 (vector 1))          ;; int[] vec1 = new int[] { 1 };
    (define vec2 vec1)                ;; int[] vec2 = vec1;
    (eq? vec1 vec2)                   ;; System.out.println(vec1 == vec2);
    (vector-set! vec1 0 2)            ;; vec1[0] = 2;
    (vector-ref vec1 0)               ;; System.out.println(vec1[0]);
    (vector-ref vec2 0)               ;; System.out.println(vec2[0]);
    
  • 3

    你是对的, eq? 比较引用以确定相等性 . 这比 equal? 更有效,它必须递归地比较对象 .

    Racket文档明确定义了每个以及相关的 eqv? 函数:

    相等?两个值相等? if和仅当它们是eqv?时,除非为特定数据类型另行指定 . 数据类型与进一步规范相等?包括字符串,字节串,对,可变对,向量,框,哈希表和可检查结构 . 在最后六个案例中,以递归方式定义了相等性;如果v1和v2都包含引用循环,则当值的无限展开相等时它们是相等的 . 示例:>(等于?'是'是)
    #T
    (等于?'是'否)
    #F
    (等于?(expt 2 100)(expt 2 100))
    #T
    (等于?2 2.0)
    #F
    (等于?(make-string 3#\ z)(make-string 3#\ z))
    #T


    eqv? eqv有两个值?当且仅当它们是eq?时,除非为特定数据类型另行指定 . 数字和字符数据类型是eqv的唯一数据类型?与eq不同?示例:>(eqv?'是'是)
    #T
    (eqv?'是'不)
    #F
    (eqv?(expt 2 100)(expt 2 100))
    #T
    (eqv?2 2.0)
    #F
    (eqv?(integer-> char 955)(integer-> char 955))
    #T
    (eqv?(make-string 3#\ z)(make-string 3#\ z))
    #F


    eq?如果v1和v2引用相同的对象,则返回#t,否则返回#f . 示例:>(eq?'是'是)
    #T
    (eq?'是'否)
    #F
    (let([v(mcons 1 2)])(eq?v v))
    #T
    (eq?(mcons 1 2)(mcons 1 2))
    #F
    (eq?(make-string 3#\ z)(make-string 3#\ z))
    #F

相关问题