diff --git a/GoldfishLang.tmu b/GoldfishLang.tmu index a793fdc..a79960b 100644 --- a/GoldfishLang.tmu +++ b/GoldfishLang.tmu @@ -96,19 +96,11 @@ (export - \ \ option option? option=? none + \ \ option none - \ \ case-integer case-integer? case-integer=? + \ \ case-integer case-char case-string - \ \ case-char case-char? case-char=? - - \ \ case-string case-string? case-string=? - - \ \ case-list case-list? case-list=? - - \ \ case-vector case-vector? case-vector=? - - \ \ case-hash-table case-hash-table? case-hash-table=? + \ \ case-list case-vector case-hash-table \ \ box @@ -130,7 +122,7 @@ \; - ;(check-set-mode! 'report-failed) + (check-set-mode! 'report-failed) \; @@ -287,6 +279,8 @@ <\goldfish-chunk|tests/goldfish/liii/lang-test.scm|true|true> (check-true ((option "str") :equals (option "str"))) + + \; @@ -389,13 +383,9 @@ - <\goldfish-chunk|goldfish/liii/lang.scm|true|true> - (define (%equals that) + - \ \ (equal? data (that 'data))) - - \; - + 该函数由define-case-class自动生成。 <\goldfish-chunk|tests/goldfish/liii/lang-test.scm|true|true> (check-true ((box 42) :equals (box 42))) @@ -491,13 +481,7 @@ - <\goldfish-chunk|goldfish/liii/lang.scm|true|true> - (define (%equals that) - - \ \ (equal? code-point (that 'code-point))) - - \; - + 该函数由自动生成。 <\goldfish-chunk|tests/goldfish/liii/lang-test.scm|true|true> (check-true ((case-char #x30) :equals (case-char #x30))) @@ -929,16 +913,10 @@ - <\goldfish-chunk|goldfish/liii/lang.scm|true|true> - (define (%equals that) - - \ \ (string=? data (that 'data))) - - \; - + 该函数由自动生成。 <\goldfish-chunk|tests/goldfish/liii/lang-test.scm|true|true> - (check-true ((box "42") :equals (box "42"))) + (check (box "42") =\ (box "42")) (check-false ((box "41") :equals (box "42"))) @@ -1181,6 +1159,14 @@ \; + <\goldfish-chunk|tests/goldfish/liii/lang-test.scm|true|true> + (check (box (list (box 1) (box 2) (box 3))) + + \ \ =\ (((box 1) :to 3) :map box)) + + \; + + <\goldfish-chunk|goldfish/liii/lang.scm|true|true> @@ -1192,7 +1178,7 @@ <\goldfish-chunk|tests/goldfish/liii/lang-test.scm|true|true> - (let1 lst (case-list '(1 2 3 4 5)) + (let1 lst (box '(1 2 3 4 5)) \ \ (check (lst :forall (lambda (x) (\ x 0))) =\ #t) diff --git a/GoldfishScheme.tmu b/GoldfishScheme.tmu index ac70c65..c11f85c 100644 --- a/GoldfishScheme.tmu +++ b/GoldfishScheme.tmu @@ -408,7 +408,7 @@ \ \ ; Extra structure - \ \ let1 \ typed-lambda typed-define define-case-class + \ \ let1 \ typed-lambda typed-define define-case-class case-class? ) @@ -3519,46 +3519,6 @@ - bool> - - 的语法糖。 - - <\scm-chunk|goldfish/liii/base.scm|true|true> - (define == equal?) - - \; - - - \; - - <\scm-chunk|tests/goldfish/liii/base-test.scm|true|true> - (check (== (list 1 2) (list 1 2)) =\ #t) - - (check (!= (list 1 2) (list 1 2)) =\ #f) - - \; - - - bool> - - 语法糖。 - - <\scm-chunk|goldfish/liii/base.scm|true|true> - (define (!= left right) - - \ \ (not (equal? left right))) - - \; - - - <\scm-chunk|tests/goldfish/liii/base-test.scm|true|true> - (check (== (list 1 2) (list 1 2)) =\ #t) - - (check (!= (list 1 2) (list 1 2)) =\ #f) - - \; - - <\scm-chunk|goldfish/liii/base.scm|true|true> @@ -3904,6 +3864,22 @@ \ \ \ \ \ \ \ (typed-define ,(cons class-name fields) + \ \ \ \ \ \ \ \ \ (define (%is-instance-of x) + + \ \ \ \ \ \ \ \ \ \ \ (eq? x ',class-name)) + + \ \ \ \ \ \ \ \ \ + + \ \ \ \ \ \ \ \ \ (typed-define (%equals (that case-class?)) + + \ \ \ \ \ \ \ \ \ \ \ (and (that :is-instance-of ',class-name) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ,@(map (lambda (field) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `(equal? ,(car field) (that ',(car field)))) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fields))) + \; \ \ \ \ \ \ \ \ \ ,@extra-operations @@ -3914,17 +3890,21 @@ \ \ \ \ \ \ \ \ \ \ \ (cond - \ \ \ \ \ \ \ \ \ \ \ \ \ ((eq? msg 'type) ',class-name) + \ \ \ \ \ \ \ \ \ \ \ \ \ ((eq? msg :is-instance-of) (apply %is-instance-of args)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ ((eq? msg :equals) (apply %equals args)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ,@(map (lambda (field) - \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ‘((eq? msg ',(car field)) ,(car field))) + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `((eq? msg ',(car field)) ,(car field))) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fields) \ \ \ \ \ \ \ \ \ \ \ \ \ ,@(map (lambda (field key-field) - \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ‘((eq? msg ,key-field) + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `((eq? msg ,key-field) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (,constructor ,@(map (lambda (f) @@ -3942,7 +3922,7 @@ \ \ \ \ \ \ \ \ \ \ \ \ \ ,@(map (lambda (op) - \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ‘((eq? msg ,(string-\symbol (string-append ":" (substring (symbol-\string (caadr op)) 1)))) + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `((eq? msg ,(string-\symbol (string-append ":" (substring (symbol-\string (caadr op)) 1)))) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (apply ,(caadr op) args))) @@ -3950,25 +3930,7 @@ \; - \ \ \ \ \ \ \ \ \ \ \ \ \ (else (value-error "No such field or operation " msg " in case class " ,class-name))))) - - \; - - \ \ \ \ \ \ \ (define (,type-pred obj) - - \ \ \ \ \ \ \ \ \ (and (procedure? obj) - - \ \ \ \ \ \ \ \ \ \ \ \ \ \ (eq? (obj 'type) ',class-name))) - - \; - - \ \ \ \ \ \ \ (typed-define (,equality-pred (p1 ,type-pred) (p2 ,type-pred)) - - \ \ \ \ \ \ \ \ \ (and ,@(map (lambda (field) - - \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ‘(equal? (p1 ',(car field)) (p2 ',(car field)))) - - \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fields)))))) + \ \ \ \ \ \ \ \ \ \ \ \ \ (else (value-error "No such field or operation " msg " in case class " ,class-name)))))))) \; @@ -3994,13 +3956,7 @@ \ \ (check-catch 'value-error (bob 'sex)) - \ \ (check-true (person? bob))) - - \; - - (check-true (person=? (person "Bob" 21) (person "Bob" 21))) - - (check-false (person=? (person "Bob" 21) (person "Bob" 20))) + \ \ (check-true (bob :is-instance-of 'person))) \; @@ -4014,7 +3970,7 @@ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (case* x - \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ((#\person?\) (x 'name)) + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ((#\procedure?\) (x 'name)) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (else (???)))))) @@ -4057,6 +4013,90 @@ \; + + + case class的前两个方法必须是。 + + <\goldfish-chunk|goldfish/liii/base.scm|true|true> + (define (case-class? x) + + \ \ (and-let* ((is-proc? (procedure? x)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ (source (procedure-source x)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ (body (source 2)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ (is-cond? (eq? (car body) 'cond)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ (at-least-2? (\= (length body) 3)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ (pred1 ((body 1) 0)) + + \ \ \ \ \ \ \ \ \ \ \ \ \ (pred2 ((body 2) 0))) + + \ \ \ \ (and (equal? pred1 '(eq? msg :is-instance-of)) + + \ \ \ \ \ \ \ \ \ (equal? pred2 '(eq? msg :equals))))) + + \; + + + <\scm-chunk|tests/goldfish/liii/base-test.scm|true|true> + (check-true (case-class? (person "Bob" 21))) + + \; + + + bool> + + 的语法糖。 + + <\scm-chunk|goldfish/liii/base.scm|true|true> + (define (== left right) + + \ \ (if (and (case-class? left) (case-class? right)) + + \ \ \ \ \ \ (left :equals right) + + \ \ \ \ \ \ (equal? left right))) + + \; + + + \; + + <\scm-chunk|tests/goldfish/liii/base-test.scm|true|true> + (check (== (list 1 2) (list 1 2)) =\ #t) + + (check (!= (list 1 2) (list 1 2)) =\ #f) + + (check-true (== (person "Bob" 21) (person "Bob" 21))) + + \; + + + bool> + + 语法糖。 + + <\scm-chunk|goldfish/liii/base.scm|true|true> + (define (!= left right) + + \ \ (not (== left right))) + + \; + + + <\scm-chunk|tests/goldfish/liii/base-test.scm|true|true> + (check (== (list 1 2) (list 1 2)) =\ #t) + + (check (!= (list 1 2) (list 1 2)) =\ #f) + + (check-true (!= (person "Bob" 20) (person "Bob" 21))) + + \; + + \; @@ -4968,7 +5008,7 @@ <\scm-chunk|goldfish/srfi/srfi-78.scm|true|true> (define-macro (check expr =\ expected) - \ \ `(check:proc ',expr (lambda () ,expr) equal? ,expected)) + \ \ `(check:proc ',expr (lambda () ,expr) == ,expected)) \; diff --git a/goldfish/liii/base.scm b/goldfish/liii/base.scm index 37a3e18..23c43dc 100644 --- a/goldfish/liii/base.scm +++ b/goldfish/liii/base.scm @@ -58,18 +58,13 @@ ; Extra routines == != loose-car loose-cdr display* in? compose identity any? ; Extra structure - let1 typed-lambda typed-define define-case-class + let1 typed-lambda typed-define define-case-class case-class? ) (begin (define* (u8-substring str (start 0) (end #t)) (utf8->string (string->utf8 str start end))) -(define == equal?) - -(define (!= left right) - (not (equal? left right))) - (define (loose-car pair-or-empty) (if (eq? '() pair-or-empty) '() @@ -160,12 +155,22 @@ fields))) `(begin (typed-define ,(cons class-name fields) + (define (%is-instance-of x) + (eq? x ',class-name)) + + (typed-define (%equals (that case-class?)) + (and (that :is-instance-of ',class-name) + ,@(map (lambda (field) + `(equal? ,(car field) (that ',(car field)))) + fields))) ,@extra-operations (lambda (msg . args) (cond - ((eq? msg 'type) ',class-name) + ((eq? msg :is-instance-of) (apply %is-instance-of args)) + ((eq? msg :equals) (apply %equals args)) + ,@(map (lambda (field) `((eq? msg ',(car field)) ,(car field))) fields) @@ -183,16 +188,26 @@ (apply ,(caadr op) args))) extra-operations) - (else (value-error "No such field or operation " msg " in case class " ,class-name))))) + (else (value-error "No such field or operation " msg " in case class " ,class-name)))))))) - (define (,type-pred obj) - (and (procedure? obj) - (eq? (obj 'type) ',class-name))) +(define (case-class? x) + (and-let* ((is-proc? (procedure? x)) + (source (procedure-source x)) + (body (source 2)) + (is-cond? (eq? (car body) 'cond)) + (at-least-2? (>= (length body) 3)) + (pred1 ((body 1) 0)) + (pred2 ((body 2) 0))) + (and (equal? pred1 '(eq? msg :is-instance-of)) + (equal? pred2 '(eq? msg :equals))))) - (typed-define (,equality-pred (p1 ,type-pred) (p2 ,type-pred)) - (and ,@(map (lambda (field) - `(equal? (p1 ',(car field)) (p2 ',(car field)))) - fields)))))) +(define (== left right) + (if (and (case-class? left) (case-class? right)) + (left :equals right) + (equal? left right))) + +(define (!= left right) + (not (== left right))) ) ; end of begin ) ; end of define-library diff --git a/goldfish/liii/lang.scm b/goldfish/liii/lang.scm index 7b1aff8..af83bba 100644 --- a/goldfish/liii/lang.scm +++ b/goldfish/liii/lang.scm @@ -18,13 +18,9 @@ (import (liii string) (liii vector) (liii list) (liii hash-table) (liii bitwise)) (export - option option? option=? none - case-integer case-integer? case-integer=? - case-char case-char? case-char=? - case-string case-string? case-string=? - case-list case-list? case-list=? - case-vector case-vector? case-vector=? - case-hash-table case-hash-table? case-hash-table=? + option none + case-integer case-char case-string + case-list case-vector case-hash-table box ) (begin @@ -78,9 +74,6 @@ (define (%unbox) data) -(define (%equals that) - (equal? data (that 'data))) - (typed-define (%to (n integer?)) (if (< n data) (case-list (list)) @@ -98,9 +91,6 @@ (define-case-class case-char ((code-point integer?)) -(define (%equals that) - (equal? code-point (that 'code-point))) - (define (%digit?) (or (and (>= code-point 48) (<= code-point 57)) @@ -168,9 +158,6 @@ (define (%length) (u8-string-length data)) -(define (%equals that) - (string=? data (that 'data))) - (define (%empty?) (string-null? data)) diff --git a/goldfish/srfi/srfi-78.scm b/goldfish/srfi/srfi-78.scm index 2228c32..3286f88 100644 --- a/goldfish/srfi/srfi-78.scm +++ b/goldfish/srfi/srfi-78.scm @@ -136,7 +136,7 @@ (else (error "unrecognized check:mode" check:mode)))) (define-macro (check expr => expected) - `(check:proc ',expr (lambda () ,expr) equal? ,expected)) + `(check:proc ',expr (lambda () ,expr) == ,expected)) (define (check-report) (if (>= check:mode 1) diff --git a/tests/goldfish/liii/base-test.scm b/tests/goldfish/liii/base-test.scm index c80c9ff..86292b7 100755 --- a/tests/goldfish/liii/base-test.scm +++ b/tests/goldfish/liii/base-test.scm @@ -657,12 +657,6 @@ (check (eof-object) => #) -(check (== (list 1 2) (list 1 2)) => #t) -(check (!= (list 1 2) (list 1 2)) => #f) - -(check (== (list 1 2) (list 1 2)) => #t) -(check (!= (list 1 2) (list 1 2)) => #f) - (check (with-output-to-string (lambda () @@ -711,17 +705,14 @@ (check (bob 'age) => 21) (check ((bob :name "hello") 'name) => "hello") (check-catch 'value-error (bob 'sex)) - (check-true (person? bob))) - -(check-true (person=? (person "Bob" 21) (person "Bob" 21))) -(check-false (person=? (person "Bob" 21) (person "Bob" 20))) + (check-true (bob :is-instance-of 'person))) (check-catch 'type-error (person 1 21)) (let ((bob (person "Bob" 21)) (get-name (lambda (x) (case* x - ((#) (x 'name)) + ((#) (x 'name)) (else (???)))))) (check (get-name bob) => "Bob") (check-catch 'not-implemented-error (get-name 1))) @@ -740,6 +731,16 @@ (check (bob :to-string) => "I am Bob 21 years old!") (check (bob :greet "Alice") => "Hi Alice, I am Bob 21 years old!")) +(check-true (case-class? (person "Bob" 21))) + +(check (== (list 1 2) (list 1 2)) => #t) +(check (!= (list 1 2) (list 1 2)) => #f) +(check-true (== (person "Bob" 21) (person "Bob" 21))) + +(check (== (list 1 2) (list 1 2)) => #t) +(check (!= (list 1 2) (list 1 2)) => #f) +(check-true (!= (person "Bob" 20) (person "Bob" 21))) + (check-report) (check (make-list 3 #\a) => (list #\a #\a #\a)) diff --git a/tests/goldfish/liii/lang-test.scm b/tests/goldfish/liii/lang-test.scm index 77be1f6..b133b00 100644 --- a/tests/goldfish/liii/lang-test.scm +++ b/tests/goldfish/liii/lang-test.scm @@ -18,7 +18,7 @@ (liii lang) (liii cut)) -;(check-set-mode! 'report-failed) +(check-set-mode! 'report-failed) (let ((opt1 (option 42)) (opt2 (option '()))) @@ -63,6 +63,7 @@ ) (check-true ((option "str") :equals (option "str"))) + (check-true ((box 42) :equals (box 42))) (check-false ((box 41) :equals (box 42))) @@ -135,7 +136,7 @@ (check ((case-string "abc") :length) => 3) (check ((case-string "中文") :length) => 2) -(check-true ((box "42") :equals (box "42"))) +(check (box "42") => (box "42")) (check-false ((box "41") :equals (box "42"))) (check-true ((case-string "") :empty?)) @@ -165,7 +166,10 @@ (check ((lst :find (lambda (x) (< x 0))) :empty?) => #t) ) -(let1 lst (case-list '(1 2 3 4 5)) +(check (box (list (box 1) (box 2) (box 3))) + => (((box 1) :to 3) :map box)) + +(let1 lst (box '(1 2 3 4 5)) (check (lst :forall (lambda (x) (> x 0))) => #t) (check (lst :forall (lambda (x) (> x 3))) => #f) )