【问题标题】:Scheme insertion sort without using primitive functions (car, cdr, cons)不使用原始函数(car、cdr、cons)的方案插入排序
【发布时间】:2018-03-21 19:41:36
【问题描述】:

我正在尝试编写带有和不带有原始函数的插入排序函数。

我的原始函数代码如下。

(define (insert n d)
  (cond ((null? n) d)
        ((null? d) n)
        (else (< (car n) (car d)) (cons (car n) (insert (cdr n) d)) (cons (car d) (insert (cdr d) n)))))

(define (sort n)
  (cond ((null? n) '())
        (else (insert (list (car n)) (sort (cdr n))))))

我应该如何修改 insert 和 sort 以不使用 car、cdr 和 cons?

编辑:我尝试编写插入函数。这就是我到目前为止所拥有的。

(define (insert n d)
  (let ((rest-digit (truncate (/ n 10))))
    (if (null? n) 0
        (+ rest-digit (insert (- n 1) d)))))

(insert '(3 2 1) '5)

编辑#2:我想我可以使用内置函数 expt。

【问题讨论】:

  • 您需要设计自己的数据表示,不使用内置的pair 数据。例如,使用闭包来表示它们。
  • @Barmar 什么是闭包?
  • 保存环境的函数。
  • 这是课堂练习还是教程练习?我希望在给出这个问题之前它会教你。
  • @katcsc 你没有回答我的问题。 let 既不是访问器也不是构造器,您不能用let 替换car。从您的更新中,您将引用列表传递给该函数。因此,您实际上至少间接地需要car 来完成任务。因此,“没有原始功能(car,cdr,cons)”是什么意思。例如。 map 肯定是使用所有这些实现的,所以是否允许?

标签: scheme


【解决方案1】:

最终您将使用原始函数。为了说明,让我向您展示一个实际使用 conscarcdr 的技巧:

(define (my-car lst)
  (apply (lambda (a . d) a) lst))

(define (my-cdr lst)
  (apply (lambda (a . d) d) lst))

(define (my-cons a d)
  (apply (lambda l l) a d))


(define test (my-cons 1 '(2 3)))
test          ; ==> (1 2 3)
(my-car test) ; ==> 1
(my-cdr test) ; ==> (2 3)

这滥用了apply 将列表作为最终参数,而其余参数按顺序被cons 编入列表的事实。 cons 不适用于所有配对:

(my-cons 1 2) ; ERROR: expected list?, got 1

您可以使conscarcdr 遵守与原始cons 相同的规则,但它们根本不是由对组成的。 Barmar 建议关闭:

(define (ccons a d)
  (lambda (f) (f a d))

(define (ccar cc)
  (cc (lambda (a d) a)))

(define (ccdr cc)
  (cc (lambda (a d) d)))

(define test2 (ccons 1 2))
test2        ; ==> #<function...>
(ccar test2) ; ==> 1
(ccdr test2) ; ==> 2

这是有效的,因为ad 在返回的函数中被关闭,并且该函数传递了这些值,因此该函数充当具有两个属性的对象。挑战在于你不能只传递一个列表,因为只有使用ccons 制作的“列表”才能使用ccarccdr

一种不太经典的方法是使用向量:

(define vtag (make-vector 0))
(define (vcons a d)
  (let ((v (make-vector 3)))
    (vector-set! v 0 vtag)
    (vector-set! v 1 a)
    (vector-set! v 2 d)
    v))

(define (vcar vl)
  (vector-ref vl 1))

(define (vcdr vl)
  (vector-ref vl 2))

(define (vpair? vl)
  (eq? vtag (vector-ref vl 0)))

或者你可以使用records:

(define-record-type :rpair
  (rcons a d)
  rpair?
  (a rcar)
  (d rcdr))

(define test (rcons 1 2))
(rpair? test) ; ==> #t
(rcar test)   ; ==> 1
(rcdr test)   ; ==> 2

现在我认为记录只是语法糖和抽象,并且在引擎盖下您所做的与矢量版本完全相同,但代码更少,但这并不是一件坏事。

编辑

所以对于 cmets,如果唯一的限制是避免 carcdrcons,但对他们的姐妹没有限制,我们不妨与他们一起实施:

(define (sort lst)
  (define (insert e lst)
    (if (null? lst)
        (list e)
        (let ((a (first lst)))
          (if (>= a e)
              (list* e lst)
              (list* a (insert e (rest lst)))))))

  (foldl insert
         '()
         lst))

(sort '(1 5 3 8 5 0 2))
; ==> (0 1 2 3 5 5 8)

当然我的第一个建议可以代替它:

(define (sort lst)
  (define (my-car lst)
    (apply (lambda (a . d) a) lst))

  (define (my-cdr lst)
    (apply (lambda (a . d) d) lst))

  (define (my-cons a d)
    (apply (lambda l l) a d))

  (define (insert e lst)
    (if (null? lst)
        (my-cons e '())
        (let ((a (my-car lst)))
          (if (>= a e)
              (my-cons e lst)
              (my-cons a (insert e (my-cdr lst)))))))

  (foldl insert
         '()
         lst))

当然,使用替换规则你可以让它变得非常荒谬:

(define (sort lst)
  ;; insert element e into lst in order
  (define (insert e lst)
    (if (null? lst)
        ((lambda l l) e)
        (let ((a (apply (lambda (a . d) a) lst)))
          (if (>= a e)
              (apply (lambda l l) e lst)
              (apply (lambda l l)
                     a
                     (insert e (apply (lambda (a . d) d) lst)))))))

  ;; main loop of sort
  ;; insert every element into acc
  (let loop ((lst lst) (acc '()))
    (if (null? lst)
        acc
        (loop (apply (lambda (a . d) d) lst)
              (insert (apply (lambda (a . d) a) lst)
                      acc)))))

【讨论】:

  • 我正在尝试在不使用 car、cdr 和 cons 的情况下编写插入和排序函数。
  • @katcsc 是的。我建议您可以使用我回答中的一种模型/方法来做到这一点。它们有不同的优点和缺点,但最终它们正在解决您的要求,因为您需要一种存储元素的方法以便对它们进行排序。如果我告诉你应该在不使用水桶的情况下将湖中的水倒到火上,你最终会用可以盛水的东西代替水桶。您可能需要使用允许使用的内容来编辑您的问题,因为无论如何我都想不出以某种方式访问​​不涉及carpair 的第一个元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多