在球拍中使用Peano数除法

时间:2019-01-29 02:58:55

标签: scheme racket

我正在尝试在球拍中使用Peano数集成算术函数。我只在使用递归(对于/ while循环则不使用)

现在,我正在从事除法工作。我不确定自己走的路是否正确,但是好像Racket给了我一个内存错误。这是我到目前为止的内容:

; Basic Peano axioms

(define (zero? n)
  (eq? n 'zero))

(define (nat? x)
  (cond
    [(zero? x) #t]
    [(pair? x) (and (eq? (first x) 'succ) (nat? (second x)))]
    [else #f]))

(define (succ n)
  (list 'succ n))

(define (pred n)
  (if (zero? n) 'zero (second n)))
; comparison of Peano numbers

(define (ltnat? m n)
  (cond
    [(zero? n) #f]
    [(zero? m) #t]
    [else (ltnat? (pred m) (pred n))]))

; Subtraction

(define (sub m n)
  (if (eq? m n)
      'zero
      (succ (sub (pred m) n)))
)

; Division

(define (div m n)
  (if (zero? m)
      'zero
      (if (eq? m n)
          '(succ zero)
          (if (ltnat? m n)
              'zero
              (succ (div (sub m n) n))))))

我已经尝试了很长时间,但是没有运气。基本上,在除法函数中,我尝试编写所有基本案例以结束递归,否则执行递归。

我也在互联网上四处搜寻,似乎没有什么适合我想要做的...

任何帮助/建议都会有所帮助。谢谢!

1 个答案:

答案 0 :(得分:5)

subdiv的定义不正确。您应该使用equal?而不是eq?来比较Peano数。

这是因为eq?测试对象 identity :当两个值是 same 对象时,而equal?测试结构相等性:例如,当两个列表具有相同顺序的相同元素时。

在这种情况下,由于您要比较在程序的不同部分中使用构造函数构建的列表,即使它们在结构上相等,它们也是不同的对象:

> (eq? 'zero 'zero) ; two constant symbols are made unique,
#t                  ; representing the same value in memory
> (eq? '(succ zero) '(succ zero)) ; two lists are read as
#f                                ; two different values
> (equal? '(succ zero) '(succ zero))
#t          ; the comparison here is done element by element
> (let ((a '(succ zero))) ; here we compare the same object
    (eq? a a))  ; the list is read only once and stored in memory
#t 

例如,您可以使用以下定义来代替sub的定义:

(define (sub m n)
  (if (equal? m n)
      'zero
      (succ (sub (pred m) n)))
)

但是,请注意,当第二个参数大于第一个参数时,此定义陷入无限循环。实际上,在递归调用中m是“递减的”,但是当它等于0时,就永远不会对其进行测试(在基本情况下)。为避免这种情况,请参见下面讨论的版本。

另一个重要的一点是,由于equal?的定义,在列表的情况下,它执行两个列表的访问,并在找到第一个列表末尾时终止,这使它成为昂贵的运算符。

因此,sub的先前定义也效率很低,因为对于递归的每个步骤,列表都是被访问的。下面是一个更为有效(正确!)的定义,其中避免了相等性测试并且正确地处理了递归:

(define (sub m n)
  (cond
    [(zero? m) 'zero]
    [(zero? n) m]
    [else (sub (pred m) (pred n))]))

最后一点:同样在div的定义中,当除数为'zero时,该函数将永远循环。从数学上讲这是正确的,因为被零除是一个不确定的运算。但是,从编程的角度来看,我认为返回某种错误会更合适。