Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

define-case-class with type and optional default value in (liii case) #237

Merged
merged 4 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 74 additions & 8 deletions GoldfishScheme.tmu
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@

<section|许可证>

<\scm-chunk|goldfish/scheme/base.scm|false|true>
<\goldfish-chunk|goldfish/scheme/base.scm|false|true>
;

; Copyright (C) 2024 The Goldfish Scheme Authors
Expand Down Expand Up @@ -179,9 +179,9 @@
;

\;
</scm-chunk>
</goldfish-chunk>

<\scm-chunk|goldfish/liii/base.scm|false|true>
<\goldfish-chunk|goldfish/liii/base.scm|false|true>
;

; Copyright (C) 2024 The Goldfish Scheme Authors
Expand Down Expand Up @@ -213,7 +213,7 @@
;

\;
</scm-chunk>
</goldfish-chunk>

\;

Expand Down Expand Up @@ -319,7 +319,7 @@
\;
</scm-chunk>

<\scm-chunk|goldfish/liii/base.scm|true|true>
<\goldfish-chunk|goldfish/liii/base.scm|true|true>
(define-library (liii base)

(import (scheme base)
Expand Down Expand Up @@ -404,14 +404,14 @@

\ \ ; Extra routines for (liii base)

\ \ == != display* in? let1 compose identity typed-lambda
\ \ == != display* in? let1 compose identity typed-lambda typed-define

)

(begin

\;
</scm-chunk>
</goldfish-chunk>

<section|测试>

Expand Down Expand Up @@ -3671,6 +3671,68 @@
\;
</scm-chunk>

<paragraph|typed-define>

<\goldfish-chunk|goldfish/liii/base.scm|true|true>
(define-macro (typed-define name-and-params body)

\ \ (let* ((name (car name-and-params))

\ \ \ \ \ \ \ \ \ (params (cdr name-and-params)))

\ \ \ \ `(define* (,name ,@(map (lambda (param)

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (let ((param-name (car param))

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (type-pred (cadr param))

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (default-value (cddr param)))

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (if (null? default-value)

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ param-name ; 无默认值时直接使用参数名

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `(,param-name ,(car default-value))))) ; 有默认值时使用默认值

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ params))

\;

\ \ \ \ \ \ \ ,@(map (lambda (param)

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (let ((param-name (car param))

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (type-pred (cadr param)))

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `(unless (,type-pred ,param-name)

\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (error 'type-error (string-append "Invalid type for " (symbol-\<gtr\>string ',param-name))))))

\ \ \ \ \ \ \ \ \ \ \ \ \ \ params)

\;

\ \ \ \ \ \ \ ,body)))

\;
</goldfish-chunk>

<\goldfish-chunk|tests/goldfish/liii/base-test.scm|true|true>
(typed-define (person (name string? "Bob") (age integer?))

\ \ (string-append name " is " (number-\<gtr\>string age) " years old"))

\;

(check (person :age 21) =\<gtr\> "Bob is 21 years old")

(check (person :name "Alice" :age 25) =\<gtr\> "Alice is 25 years old")

(check-catch 'type-error (person :name 123 :age 25))

\;
</goldfish-chunk>

\;

<section|结尾>
Expand Down Expand Up @@ -5196,7 +5258,7 @@
<paragraph|define-case-class>

<\scm-chunk|tests/goldfish/liii/case-test.scm|true|true>
(define-case-class person ((name "Bob") (age 21)))
(define-case-class person ((name string? "Bob") (age integer?)))

\;

Expand All @@ -5209,6 +5271,10 @@
\ \ (check ((bob :name "hello") 'name) =\<gtr\> "hello"))

\;

(check-catch 'type-error (person 1 21))

\;
</scm-chunk>

<paragraph|case*><index|case*>
Expand Down
23 changes: 22 additions & 1 deletion goldfish/liii/base.scm
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
; SRFI-8
receive
; Extra routines for (liii base)
== != display* in? let1 compose identity typed-lambda
== != display* in? let1 compose identity typed-lambda typed-define
)
(begin

Expand Down Expand Up @@ -116,6 +116,27 @@
args)
,@body))))

(define-macro (typed-define name-and-params body)
(let* ((name (car name-and-params))
(params (cdr name-and-params)))
`(define* (,name ,@(map (lambda (param)
(let ((param-name (car param))
(type-pred (cadr param))
(default-value (cddr param)))
(if (null? default-value)
param-name ; 无默认值时直接使用参数名
`(,param-name ,(car default-value))))) ; 有默认值时使用默认值
params))

,@(map (lambda (param)
(let ((param-name (car param))
(type-pred (cadr param)))
`(unless (,type-pred ,param-name)
(error 'type-error (string-append "Invalid type for " (symbol->string ',param-name))))))
params)

,body)))

) ; end of begin
) ; end of define-library

11 changes: 3 additions & 8 deletions goldfish/liii/case.scm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
;

(define-library (liii case)
(import (liii base))
(export case* define-case-class)
(begin

Expand All @@ -24,17 +25,12 @@
(string->symbol (string-append ":" (symbol->string (car field)))))
fields)))
`(begin
;; 定义构造函数
(define* (,constructor ,@(map (lambda (field)
`(,(car field) ,(cadr field)))
fields))
(typed-define ,(cons class-name fields)
(lambda (msg . args)
(cond
;; 字段访问
,@(map (lambda (field)
`((eq? msg ',(car field)) ,(car field)))
fields)
;; 字段更新
,@(map (lambda (field key-field)
`((eq? msg ,key-field)
(,constructor ,@(map (lambda (f)
Expand All @@ -43,8 +39,7 @@
(car f)))
fields))))
fields key-fields)
;; 未知消息
(else (error "Unknown message"))))))))
(else (value-error "Unknown message" msg))))))))

; 0 clause BSD, from S7 repo case.scm
(define case*
Expand Down
7 changes: 7 additions & 0 deletions tests/goldfish/liii/base-test.scm
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,13 @@
(check (add3 1 2 3) => 6)
(check-catch 'type-error (add3 1.2 2 3))

(typed-define (person (name string? "Bob") (age integer?))
(string-append name " is " (number->string age) " years old"))

(check (person :age 21) => "Bob is 21 years old")
(check (person :name "Alice" :age 25) => "Alice is 25 years old")
(check-catch 'type-error (person :name 123 :age 25))

(check-report)

(check (make-list 3 #\a) => (list #\a #\a #\a))
Expand Down
4 changes: 3 additions & 1 deletion tests/goldfish/liii/case-test.scm
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

(check-set-mode! 'report-failed)

(define-case-class person ((name "Bob") (age 21)))
(define-case-class person ((name string? "Bob") (age integer?)))

(let1 bob (person :name "Bob" :age 21)
(check (bob 'name) => "Bob")
(check (bob 'age) => 21)
(check ((bob :name "hello") 'name) => "hello"))

(check-catch 'type-error (person 1 21))

; 0 clause BSD, from S7 repo s7test.scm
(define (scase x)
(case* x
Expand Down
Loading