正如 amalloy 在评论中所说,这确实是一道数学题。这种编码之所以有效,是因为算术的基本定理,即任何自然数(正整数或零)都具有唯一的素数分解。
因此,您可以使用一个或多个额外的素因子对整数的符号进行编码(实际上,您只需要一个,因为您可以将事物写为 2^a3^b5^s ,其中 s 是[0,3] 对两个元素的符号进行编码)。
另一种方法是简单地使用现有的表示,但将整数映射到自然数。这很好,因为它是一个实际证明,没有比自然数更多的整数。这样的地图可能是:
- 如果 i >= 0 则 2i。
- 否则 -2i - 1.
很容易看出这是一个one-to-one 对应关系,而且0 映射到0(这使得0 成为nil 的一个很好的值)。
这是这些地图,写在(对不起)打字球拍,因为我正在努力弄清楚我是否可以使用它。
(define (Z->N (i : Integer)) : Natural
;; map an integer to a natural
(if (>= i 0)
(* i 2)
(- (* (- i) 2) 1)))
(define (N->Z (n : Natural)) : Integer
;; map the naturals into the integers
(let-values ([(q r) (quotient/remainder n 2)])
(if (zero? r)
q
(- (- q) 1))))
现在你的实现还有另一个问题:它会很乐意处理不是 2^a3^b 形式的数字,例如任何具有其他素因数的数字。处理这个问题的方法是在提取幂时检查数字是否具有该形式:实际上这意味着检查数字是否为 2^a*3^b*1 形式。
所以下面的代码就是这样做的,以及上面的编码整数。这又是在类型化的 Racket 中(对不起,再次),它还利用了多个值以及可能仅存在于 Racket 中的其他一些东西。
(define (defactor (n : Natural) (p : Natural)) : (Values Natural Natural)
;; Given n and a factor p, return m where p does not divide m,
;; and j, the number of factors of p removed (so n = m*p^j)
(let df-loop ([m : Natural n]
[j : Natural 0])
(let-values ([(q r) (quotient/remainder m p)])
(if (zero? r)
(df-loop q (+ j 1))
(values m j)))))
(define (kar&kdr (k : Natural)) : (Values Integer Integer)
;; Given something which should be a kons, return its kar & kdr.
;; If it is not a kons signal an error
(let*-values ([(k2 encoded-kar) (defactor k 2)]
[(k23 encoded-kdr) (defactor k2 3)])
(unless (= k23 1)
(error 'kar&kdr "not a cons"))
(values (N->Z encoded-kar) (N->Z encoded-kdr))))
(define (kons (the-kar : Integer) (the-kdr : Integer)) : Natural
(* (expt 2 (Z->N the-kar))
(expt 3 (Z->N the-kdr))))
(define (kar (the-kons : Natural)) : Integer
(let-values ([(the-kar the-kdr) (kar&kdr the-kons)])
the-kar))
(define (kdr (the-kons : Natural)) : Integer
(let-values ([(the-kar the-kdr) (kar&kdr the-kons)])
the-kdr))
现在
> (define d (kons 123 -456))
> d
- : Integer [more precisely: Nonnegative-Integer]
51385665200410193914365219310409629004573395973849642473134969706165383608831740620563388986738635202925909198851954060195023302783671526117732269828652603388431987979605951272414330987611274752111186624164906143978901704325355283206259678088536996807776750955110998323447711166379786727609752016045005681785186498933895920793982869940159108073471074955985333560653268614500306816876936016985137986665262182684386364851688838680773491949813254691225004097103180392486216812280763694296818736638062547181764608
> (kar d)
- : Integer
123
> (kdr d)
- : Integer
-456
> (kdr (+ d 1))
kar&kdr: not a cons [,bt for context]