2017-04-06 2 views
1

Es scheint, dass Scheme Ganzzahl- und Gleitkomma-Versionen einer Reihe hält, anders zu sein, wenn gleich mit ?, aber das gleiche, wenn = mit ihnen vergleichen:rekursive numerische Gleichheit in Schema

(equal? 2 2.0) ; => #f 
(= 2 2.0)  ; => #t 

Allerdings, wenn ich haben Sie eine rekursive Struktur mit einigen numerischen Teilen (oder sogar eine einfache Liste von Zahlen), gibt es eine Methode, um sie zu vergleichen, die = für numerische Vergleiche verwendet?

(equal? '(2 3) '(2.0 3.0)) ; => #f 
(= '(2 3) '(2.0 3.0))  ; error: contract violation 

Ich kann meine eigene Gleichheit checker, so etwas schreiben:

(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))))) 

Aber es scheint, als ob dies eine gemeinsame Aufgabe genug sein würde, das Schema könnte eine eingebaute Methode, dies zu tun.

Antwort

3

In Racket Sie kann den Begriff der Gleichheit, die Sie mit Hilfe der equal?/recur eingebauten Prozedur bauen:

;; 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 

Die equal?/recur Verfahren Griffe durch Paare wiederkehrende Strukturen usw.

2

Schema ist eine minimalistische Sprache und hat nur sehr wenige Primitive. 2 und 2.0 sind nicht die gleiche Nummer, weil 2.0 niedriger und höher als 2 sein kann, was die genaue Menge 2 ist.

Wenn Sie eine Liste mit Zahlen und möchten überprüfen, ob alle gleich mit = sind, können Sie es every von SRFI-1 List Library tun mit:

;; 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 

In R6RS es wird einfacher:

#!r6rs 

(import (rnrs base) 
     (only (srfi :1) every)) 

(every = '(2 3) '(2.0 3.0)) ; ==> #t 

Und da Sie Racket getaggt haben, gibt es eine Chance, dass Sie vielleicht nicht schreiben Scheme aber vielleicht #lang racket, die sowohl Unterstützung für SRFI-1 und seine eigene Version every, dieheißt:

#lang racket 

(andmap = '(2 3) '(2.0 3.0)) ; ==> #t 

(require srfi/1) 
(every = '(2 3) '(2.0 3.0)) ; ==> #t 

EDIT

Eine generische Lösung für alle Baumstrukturen, die sich für die Baumstruktur verwenden und equal? wenn es keine weiteren typspezifische Optionen sind:

(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 
+1

Ah, das ist eine schöne Lösung für Listen von Zahlen. Es klingt dann wie für komplexere Strukturen, wie '(a 2 (b 3)) vs.' (a 2.0 (b 3.0)), müssen Sie möglicherweise eine benutzerdefinierte Funktion schreiben. –

+0

@ JeffAmes Ich habe in einem Beispiel der Herstellung eines generischen gleich Maker bearbeitet, wo Sie angeben können, wie einige Typen verglichen werden sollen. – Sylwester