guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: define-typed: checking values on proc entry and exit


From: Dr. Arne Babenhauserheide
Subject: Re: define-typed: checking values on proc entry and exit
Date: Tue, 14 May 2024 03:34:46 +0200
User-agent: mu4e 1.12.4; emacs 30.0.50

Vivien Kraus <vivien@planete-kraus.eu> writes:

> Hello!
>
> This is an interesting approach, thank you.
>
> Le vendredi 10 mai 2024 à 09:47 +0200, Dr. Arne Babenhauserheide a
> écrit :
>> │       ;; get the result
>> │       (let ((res (helper)))
>> │         ;; typecheck the result
>> │         (unless (ret? res)
>> │           (error "type error: return value ~a does not match ~a"
>> │                  res ret?))
>> │         ;; return the result
>> │         res))
>
> A nice improvement would be to support multiple return values, for
> instance by using call-with-values, and checking the return value with
> (apply ret? res) instead of (ret? res).
>
> What do you think?

That’s a nice idea!

With some experimentation I got it working:

┌────
│ (import (srfi :11 let-values))
│ (define-syntax-rule (define-typed (procname args ...) (ret? types ...) body 
...)
│   (begin
│     (define (procname args ...)
│       ;; create a sub-procedure to run after typecheck
│       (define (helper)
│         body ...)
│       ;; use a typecheck prefix for the arguments
│       (map (λ (type? argument)
│              (unless (type? argument)
│                (error "type error ~a ~a" type? argument)))
│            (list types ...) (list args ...) )
│       ;; get the result
│       (let-values ((res (helper)))
│         ;; typecheck the result
│         (unless (apply ret? res)
│           (error "type error: return value ~a does not match ~a"
│                  res ret?))
│         ;; return the result
│         (apply values res)))
│     ;; add procedure properties via an inner procedure
│     (let ((helper (lambda (args ...) body ...)))
│       (set-procedure-properties! procname (procedure-properties helper))
│       ;; preserve the name
│       (set-procedure-property! procname 'name 'procname))))
└────

This supports most features of regular define like docstrings, procedure
properties, multiple values (thanks to Vivien!), and so forth.

┌────
│ (define-typed (hello typed-world) (string? string?)
│   typed-world)
│ (hello "typed")
│ ;; => "typed"
│ (hello 1337)
│ ;; => type error ~a ~a #<procedure string? (_)> 1337
│ (define-typed (hello typed-world) (string? string?)
│   "typed"
│   #((props))
│   typed-world)
│ (procedure-properties hello)
│ ;; => ((name . hello) (documentation . "typed") (props))
│ (define-typed (multiple-values num) ((λ(a b) (> a b)) number?)
│   (values (* 2 (abs num)) num))
│ (multiple-values -3)
│ ;; => 6
│ ;; => -3
└────


Best wishes,
Arne

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]