Scheme 中的递归数值相等

问题描述 投票:0回答:2

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 可能有一个内置方法来执行此操作。

recursion scheme racket equality r5rs
2个回答
3
投票

在 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
过程通过对、结构等处理重复。


2
投票

Scheme 是一种极简语言,具有很少的原语。

2
2.0
不是相同的数字,因为
2.0
可以低于或高于
2
,即确切的量
2

如果您有一个包含数字的列表,并希望检查所有数字是否与

=
相同,您可以使用 SRFI-1 列表库
中的 
every 来完成:

;; 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
© www.soinside.com 2019 - 2024. All rights reserved.