【问题标题】:Anomalous Behavior Comparing Lists in DrRacketDrRacket 中的异常行为比较列表
【发布时间】:2016-04-22 23:13:25
【问题描述】:

我正在尝试编写一个程序来检查列表列表是否具有特定属性(对问题不重要)。在此过程中,我发现有必要生成单个给定列表的“非对角对”列表,因此我编写了一个宏,它接受一个列表并定义对列表(笛卡尔积的列表版本集)以及我称之为该列表的“对角线”('(x x) 形式的对)。我为此编写的代码如下:

;;;These first two definitions are 'extended' car and cdr
;;;I only did this because the (prod a b) code below threw errors otherwise
(define (xcar a) (cond ((null? a) '()) ((car a))))
(define (xcdr a) (cond ((null? a) '()) ((cdr a))))

;;;This defines a pre-product, i.e. all pairs with the first element of the first list
(define (pre-prod a b)
    (cond ((or (null? a) (null? b)) '())
    ((append (list (list (xcar a) (xcar b))) (pre-prod a (xcdr b))))))

;;;This defines the full product of the list
(define (prod a b)
    (cond ((null? a) '())
    ((append (pre-prod a b) (prod (xcdr a) b)))))

;;;This defines the diagonal of the list
(define (diagonal a)
    (cond ((null? a) '())
    ((append
      (list (list (car a) (car a)))
      (diagonal (cdr a))))))

太好了,所有代码似乎都按我想要的那样工作。接下来我需要获取 set-minus 的列表版本。我在an answer here 中找到了以下代码来执行此操作:

;;;Returns #t if x is an element of lst and #f otherwise
(define (element? x lst)
    (cond ((null? lst) #f)
    ((eq? x (car lst)) #t)
    (#t (element? x (cdr lst)))))

;;;Takes list a and removes all elements of list b from it
(define (list-minus a b)
    (cond ((null? a) '())
    ((element? (car a) b)
     (list-minus (cdr a) b))
    (#t (cons (car a) (list-minus (cdr a) b)))))

很酷,这似乎可以很好地完成它需要做的事情。现在我要做的就是让 DrRacket 返回正确对的列表(删除对角线)。我认为以下代码应该这样做:

(define (proper-pairs a) (list-minus (prod a a) (diagonal a)))

现在我用一些简单的方法测试这个新函数,它应该返回'()

>  (proper-pairs '(1))
=> '((1 1))

什么?我尝试了很多示例,多次修改代码,在各种列表中尝试过。我总是想出以下问题:list-minus will not remove a list from a list of lists.

问题 1:为什么list-minus 在列表列表中表现出这种异常行为,同时在以下示例中完全按预期工作:

>  (list-minus '(1 2 3 4 5) '(x 2 4 m))
=> '(1 3 5)

问题2:如何修复list-minus代码,还是需要从头开始?

问题 3: 在上面的第一行代码中,我必须“扩展”carcdr 以确保 prod 函数不会引发错误。我做的是标准把戏吗?我不确定我是否理解它为什么会有所作为(我只是试了一下,因为我有预感它可能会起作用)。

免责声明:我不是程序员。我正在尝试学习函数式编程,以此来测试各种(数学)猜想并编译一些示例。除了在 DrRacket 和旧的 TI-83 计算器上完成的一些非常愚蠢的小代码之外,我完全没有编写代码的经验。话虽如此,可能有必要为我“简化”您的答案。

抱歉啰嗦了,感谢您的宝贵时间!

【问题讨论】:

  • (eq? '(1) '(1)) ; ==> #f(equal? '(1) '(1)) ; ==> #t

标签: list racket


【解决方案1】:

问题是由于 Racket 中的相等性,就像在其他语言中一样,用不同的运算符表示,必须根据以下条件选择:

  1. 必须比较的数据类型,

  2. 比较的语义。

一般的提示是你应该使用逻辑上更简单的操作符,并且可以用于某种比较。

例如,您应该使用=compare numberseq?compare objects for identity 即两个值相等,如果它们是内存中的 same 对象; eqv? 如果你想检查这两个值 are the same object in memory or are equal numbers or equal characters; equal? 如果您想检查两个值是否为 eqv? 或者它们是否是相等的字符串,或者它们是像列表这样的结构化数据,是否在结构上等效(参见 the manual),即递归等价。

例如:

(equal? '(a (b)) '(a (b)))  ; => true, two different objects with the same structure
(eqv? '(a (b)) '(a (b)))    ; => false, two different objects
(eq? '(a (b)) '(a (b)))     ; => false, as for eqv?
(let ((x '(a (b))))
  (eq? x x))                ; true, they are the same object

【讨论】:

  • 我将eq? 更改为equal?,现在它的运行方式也完全符合我的要求!非常感谢您非常清晰和有用的回答!
猜你喜欢
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 2022-12-18
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多