Scheme 中的递归数值相等
Recursive numeric equality in Scheme
似乎 Scheme 认为整数和浮点数的版本在使用 equal? 时是不同的,但在使用 = 比较它们时是相同的:
(equal? 2 2.0) ; => #f
(= 2 2.0) ; => #t
但是,如果我有一个包含一些数字部分的递归结构(或者甚至是一个简单的数字列表),是否有使用 = 进行数字比较的方法来比较它们?
(equal? '(2 3) '(2.0 3.0)) ; => #f
(= '(2 3) '(2.0 3.0)) ; error: contract violation
我可以编写自己的相等性检查程序,如下所示:
(define myequal?
(lambda (x y)
(cond ((and (null? x) (null? y)) #t)
((or (null? x) (null? y)) #f)
((and (pair? x) (pair? y))
(and (myequal? (car x) (car y))
(myequal? (cdr x) (cdr y))))
((or (pair? x) (pair? y)) #f)
((and (number? x) (number? y)) (= x y))
((or (number? x) (number? y)) #f)
(else (equal? x y)))))
但这似乎是一个足够常见的任务,Scheme 可能有一个内置方法来执行此操作。
Scheme 是一种极简语言,原语很少。 2
和 2.0
不是同一个数字,因为 2.0
可以低于也可以高于 2
,后者是 2
的确切数量。
如果您有一个包含数字的列表,并希望检查所有内容是否与 =
相同,您可以使用 every
from SRFI-1 List Library:
;; include the library. In R5RS this is impleentation specific
;; and worst case you need to load of external file to be portable.
(load "srfi1.scm")
(every = '(2 3) '(2.0 3.0)) ; ==> #t
在 R6RS 中它变得更简单:
#!r6rs
(import (rnrs base)
(only (srfi :1) every))
(every = '(2 3) '(2.0 3.0)) ; ==> #t
并且由于您已经标记了 Racket,因此您可能不会编写 Scheme,但可能 #lang racket
既支持 SRFI-1 又支持自己的 every
版本,称为 andmap
:
#lang racket
(andmap = '(2 3) '(2.0 3.0)) ; ==> #t
(require srfi/1)
(every = '(2 3) '(2.0 3.0)) ; ==> #t
编辑
所有树结构的通用解决方案,将自身用于树结构和 equal?
当没有更多类型特定选项时:
(define (make-equal . predicates-and-equal-procedures)
(when (odd? (length predicates-and-equal-procedures))
(error "make-equal needs an even number of predicate and equal function arguments"))
(define (mequal? a b)
(if (pair? a)
(and (pair? b)
(mequal? (car a) (car b))
(mequal? (cdr a) (cdr b)))
(let loop ((pe predicates-and-equal-procedures))
(if (null? pe)
(equal? a b)
(let ((p? (car pe)))
(if (p? a)
(and (p? b)
((cadr pe) a b))
(loop (cddr pe))))))))
mequal?)
(define list=?
(make-equal number? =))
(list=? '(1 2 a b "test") '(1.0 2 a b "test")) ; ==> #t
(define equal-ci?
(make-equal string? string-ci=? char? char-ci=?))
(equal-ci? '(1 2 a b "Test") '(1 2 a b "test")) ; ==> #t
(define inexact-eq-ci?
(make-equal number? = string? string-ci=? char? char-ci=?))
(inexact-eq-ci? '(1 2 a b "test") '(1.0 2 a b "TEST")) ; ==> #t
在 Racket 中,您可以在 equal?/recur
内置过程的帮助下构建您想要的平等概念:
;; equalish? : Any Any -> Boolean
;; Like equal?, but use = for numbers (including within compound data)
(define (equalish? a b)
(if (and (number? a) (number? b))
(= a b)
(equal?/recur a b equalish?)))
(equalish? '(2 3) '(2.0 3.0))
;; => #t
equal?/recur
过程通过对、结构等处理循环
似乎 Scheme 认为整数和浮点数的版本在使用 equal? 时是不同的,但在使用 = 比较它们时是相同的:
(equal? 2 2.0) ; => #f
(= 2 2.0) ; => #t
但是,如果我有一个包含一些数字部分的递归结构(或者甚至是一个简单的数字列表),是否有使用 = 进行数字比较的方法来比较它们?
(equal? '(2 3) '(2.0 3.0)) ; => #f
(= '(2 3) '(2.0 3.0)) ; error: contract violation
我可以编写自己的相等性检查程序,如下所示:
(define myequal?
(lambda (x y)
(cond ((and (null? x) (null? y)) #t)
((or (null? x) (null? y)) #f)
((and (pair? x) (pair? y))
(and (myequal? (car x) (car y))
(myequal? (cdr x) (cdr y))))
((or (pair? x) (pair? y)) #f)
((and (number? x) (number? y)) (= x y))
((or (number? x) (number? y)) #f)
(else (equal? x y)))))
但这似乎是一个足够常见的任务,Scheme 可能有一个内置方法来执行此操作。
Scheme 是一种极简语言,原语很少。 2
和 2.0
不是同一个数字,因为 2.0
可以低于也可以高于 2
,后者是 2
的确切数量。
如果您有一个包含数字的列表,并希望检查所有内容是否与 =
相同,您可以使用 every
from SRFI-1 List Library:
;; include the library. In R5RS this is impleentation specific
;; and worst case you need to load of external file to be portable.
(load "srfi1.scm")
(every = '(2 3) '(2.0 3.0)) ; ==> #t
在 R6RS 中它变得更简单:
#!r6rs
(import (rnrs base)
(only (srfi :1) every))
(every = '(2 3) '(2.0 3.0)) ; ==> #t
并且由于您已经标记了 Racket,因此您可能不会编写 Scheme,但可能 #lang racket
既支持 SRFI-1 又支持自己的 every
版本,称为 andmap
:
#lang racket
(andmap = '(2 3) '(2.0 3.0)) ; ==> #t
(require srfi/1)
(every = '(2 3) '(2.0 3.0)) ; ==> #t
编辑
所有树结构的通用解决方案,将自身用于树结构和 equal?
当没有更多类型特定选项时:
(define (make-equal . predicates-and-equal-procedures)
(when (odd? (length predicates-and-equal-procedures))
(error "make-equal needs an even number of predicate and equal function arguments"))
(define (mequal? a b)
(if (pair? a)
(and (pair? b)
(mequal? (car a) (car b))
(mequal? (cdr a) (cdr b)))
(let loop ((pe predicates-and-equal-procedures))
(if (null? pe)
(equal? a b)
(let ((p? (car pe)))
(if (p? a)
(and (p? b)
((cadr pe) a b))
(loop (cddr pe))))))))
mequal?)
(define list=?
(make-equal number? =))
(list=? '(1 2 a b "test") '(1.0 2 a b "test")) ; ==> #t
(define equal-ci?
(make-equal string? string-ci=? char? char-ci=?))
(equal-ci? '(1 2 a b "Test") '(1 2 a b "test")) ; ==> #t
(define inexact-eq-ci?
(make-equal number? = string? string-ci=? char? char-ci=?))
(inexact-eq-ci? '(1 2 a b "test") '(1.0 2 a b "TEST")) ; ==> #t
在 Racket 中,您可以在 equal?/recur
内置过程的帮助下构建您想要的平等概念:
;; equalish? : Any Any -> Boolean
;; Like equal?, but use = for numbers (including within compound data)
(define (equalish? a b)
(if (and (number? a) (number? b))
(= a b)
(equal?/recur a b equalish?)))
(equalish? '(2 3) '(2.0 3.0))
;; => #t
equal?/recur
过程通过对、结构等处理循环