From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "Dr. Arne Babenhauserheide" Newsgroups: gmane.lisp.guile.devel,gmane.lisp.guile.user Subject: Re: define-typed: checking values on proc entry and exit Date: Wed, 15 May 2024 02:10:10 +0200 Message-ID: <87r0e4szod.fsf@web.de> References: <871q6axg4s.fsf@web.de> <97402bb8-b4e9-44a1-9955-23e95eda6f5d@posteo.de> <87v83huq87.fsf@web.de> Mime-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="1920"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: mu4e 1.12.4; emacs 30.0.50 To: guile-user@gnu.org, Zelphir Kaltstahl , guile-devel@gnu.org Original-X-From: guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org Wed May 15 02:10:52 2024 Return-path: Envelope-to: guile-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1s72EN-0000Bj-30 for guile-devel@m.gmane-mx.org; Wed, 15 May 2024 02:10:51 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1s72Dq-0003af-Hc; Tue, 14 May 2024 20:10:18 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s72Do-0003aI-VF; Tue, 14 May 2024 20:10:16 -0400 Original-Received: from mout.web.de ([212.227.17.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1s72Dm-0000iy-P7; Tue, 14 May 2024 20:10:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=web.de; s=s29768273; t=1715731811; x=1716336611; i=arne_bab@web.de; bh=RnyQN4Por6SblouR02k96bQhYPVzhA9qtX5va09yLv4=; h=X-UI-Sender-Class:From:To:Subject:In-Reply-To:References:Date: Message-ID:MIME-Version:Content-Type:cc:content-transfer-encoding: content-type:date:from:message-id:mime-version:reply-to:subject: to; b=pKQxYCi/OSz2dXzeu0ARhIJFdXdat/aTXpBNZ+7R54FgoK5CBKNcMb4WJTEc6qiD klBKTHaVlgCoRJ0Vh+Isx8r5Nq1bJzIeU9rrKm5JskZvWHKfVEUggDa6uAkBzIqe1 EYtzmeciZrhr5JKEUMsoIEQur9HHiuRywomYq4wT09jq5tHRrhBj2lyUYwQezdb3e RNlWu15gkWch/+V2DUc0hJuilbALQT1tcuRYdrdjlRjUoIiNt7o2n+OCtXtHUs7so qGhHxV7r/jn01JrY/YM/J+DgUdyF0C+rkzSiRd2BkmM7ebJ5FUkMZ7lI2/RJ8TiNN X1JQWbbgn91zPOvcuQ== X-UI-Sender-Class: 814a7b36-bfc1-4dae-8640-3722d8ec6cd6 Original-Received: from fluss ([80.136.28.187]) by smtp.web.de (mrweb105 [213.165.67.124]) with ESMTPSA (Nemesis) id 1MECGl-1sGcSc37Cv-004iXk; Wed, 15 May 2024 02:10:11 +0200 In-Reply-To: <87v83huq87.fsf@web.de> (Arne Babenhauserheide's message of "Tue, 14 May 2024 03:39:04 +0200") X-Provags-ID: V03:K1:PfCqxEoCxVIZA4dBB/ZRN57qMqTgxYsP4zvMXfC/z+cJGRDla5e d+n5u95i1mHPLCJY0yTNf2Kb2q48hYNVInKibwIpPD6rzdtna/FgG2C0YMK9nv3XYAbq5HW QCgqkDq0p1qEZc6PrYayWuS59YCen+mIFheNw6v3AwFwbwCF3ahM7dWkd0+miAWeo/hvfRn ilLexmEjcMxG90YqwG2fQ== UI-OutboundReport: notjunk:1;M01:P0:iAVYUSQpVO8=;4ag4M+HjBCSvF1ClBaZlJ43vwbw orROQpkmyeqEojfrYy9YvroGL4OyY+g3v3K0wBUbQkTTuB569qC9pmZB9J/xpow8rsxc7J1BN bHBQ0mtzQ7z6lASoKVFLP9djoQZfIu2ULckypPrBzd1Dz8rat44LOsjyL+X9JS1YBsIzX0Qjc /SVUuo8FObiHv5dTXB0wmQIztfrZ/fwI3FXTUGEdtg0Of1c04xvS0ubeG83gfzVdB5yLD5H5E qSXoAMF9bRIyk1RNEbEHPpg9uRP8naMgy/9J47NWrNryJMP8MfQ3qv6jfvTyRN8ZNnuIlG5uP YIdz0CExqq1VVloXq1APQunfpbokKBXmZFeiOqpbDALTPW2hUxUIFX7ZbNaAQqemqaZdV3x0M hWpdi0fefkYvR7uG46Y+6qO1TU59UN1Z2/uUZsv2h9q/uP7/fTsfBv3AWQAcmtozHERtiAsCu IXEkiN1m+mIr87xpojxG3pXcA+GUvy2pz0gw0TqemwLIGThThvIgrSXf0L6DuNh5XkMhgIPpL 4niXHQeD3ZqSRqceuV2WnVIq19n8SDbmiLAEEmtjXLux5jxNmo0REOXV4/oI9fM8GgffIyHKf SvilMx1xAKJD24JN8v3M+Q9K72C4igSl9542XpoLtpbnhzt62Jl6SZWPUetTw0ZTI+ZynYpih 0vfbf8dnbt7fSSo5ZCts3orb1Q4Ymg0Cc00KveQZr4Zw5CagZ6mBY2bXPB1qDVScJwGfZEcEE PhvpNoGocnvZENDPThydznYgojhbE9SNmwDDVn35+N0TTwi3IWxZN8GdDP7abigA4+WpA3Hx Received-SPF: pass client-ip=212.227.17.11; envelope-from=arne_bab@web.de; helo=mout.web.de X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org Original-Sender: guile-devel-bounces+guile-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.lisp.guile.devel:22419 gmane.lisp.guile.user:19650 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable "Dr. Arne Babenhauserheide" writes: > Zelphir Kaltstahl writes: >> https://codeberg.org/ZelphirKaltstahl/guile-examples/src/commit/0e231c28= 9596cb4c445efb30168105914a8539a5/macros/contracts > And the *-versions are ominous: optional and keyword arguments may be > the next frontier. > > I=E2=80=99m not sure how to keep those simple. I now have a solution: https://www.draketo.de/software/guile-snippets#defin= e-typed =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (import (srfi :11 let-values)) =E2=94=82 (define-syntax-rule (define-typed (procname args ...) (ret? types= ...) body ...) =E2=94=82 (begin =E2=94=82 (define* (procname args ...) =E2=94=82 ;; create a sub-procedure to run after typecheck =E2=94=82 (define (helper) =E2=94=82 body ...) =E2=94=82 ;; use a typecheck prefix for the arguments=20=20=20 =E2=94=82 (map (=CE=BB (type? argument) =E2=94=82 (let ((is-keyword? (and (keyword? type?) =E2=94=82 (keyword? argument)))) =E2=94=82 (when (and is-keyword? (not (equal? type? argument= ))) =E2=94=82 (error "Keywords in arguments and types are not = equal ~a ~a" =E2=94=82 type? argument)) =E2=94=82 (unless (or is-keyword? (type? argument)) =E2=94=82 (error "type error ~a ~a" type? argument)))) =E2=94=82 (list types ...) (list args ...)) =E2=94=82 ;; get the result =E2=94=82 (let-values ((res (helper))) =E2=94=82 ;; typecheck the result =E2=94=82 (unless (apply ret? res) =E2=94=82 (error "type error: return value ~a does not match ~a" =E2=94=82 res ret?)) =E2=94=82 ;; return the result =E2=94=82 (apply values res))) =E2=94=82 (unless (equal? (length (quote (args ...))) (length (quote (t= ypes ...)))) =E2=94=82 (error "argument error: argument list ~a and type list ~a h= ave different size" =E2=94=82 (quote (args ...)) (quote (types ...)))) =E2=94=82 ;; add procedure properties via an inner procedure =E2=94=82 (let ((helper (lambda* (args ...) body ...))) =E2=94=82 (set-procedure-properties! procname (procedure-properties h= elper)) =E2=94=82 ;; preserve the name =E2=94=82 (set-procedure-property! procname 'name 'procname)))) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 This supports most features of regular define like docstrings, procedure properties, multiple values (thanks to Vivien!), keyword-arguments (thanks to Zelphir Kaltstahl=E2=80=99s [contracts]), and so forth. Basic usage: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (define-typed (hello typed-world) (string? string?) =E2=94=82 typed-world) =E2=94=82 (hello "typed") =E2=94=82 ;; =3D> "typed" =E2=94=82 (hello 1337) =E2=94=82 ;; =3D> type error ~a ~a # 1337 =E2=94=82 (define-typed (hello typed-world) (string? string?) =E2=94=82 "typed" ;; docstring =E2=94=82 #((props)) ;; more properties =E2=94=82 1337) ;; wrong return type =E2=94=82 (procedure-documentation hello) =E2=94=82 ;; =3D> "typed" =E2=94=82 (procedure-properties hello) =E2=94=82 ;; =3D> ((name . hello) (documentation . "typed") (props)) =E2=94=82 (hello "typed") =E2=94=82 ;; type error: return value ~a does not match ~a (1337) # =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Multiple Values and optional and required keyword arguments: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (define-typed (multiple-values num) ((=CE=BB(a b) (> a b)) number= ?) =E2=94=82 (values (* 2 (abs num)) num)) =E2=94=82 (multiple-values -3) =E2=94=82 ;; =3D> 6 =E2=94=82 ;; =3D> -3 =E2=94=82 (define-typed (hello #:key typed-world) (string? #:key string?) "= typed" #((props)) typed-world) =E2=94=82 (hello #:typed-world "foo") =E2=94=82 ;; =3D> "foo" =E2=94=82 ;; unused keyword arguments are always boolean #f as input =E2=94=82 (hello) =E2=94=82 ;; =3D> type error ~a ~a # #f =E2=94=82 ;; typing optional keyword arguments =E2=94=82 (define (optional-string? x) (or (not x) (string? x))) =E2=94=82 (define-typed (hello #:key typed-world) (string? #:key optional-s= tring?) =E2=94=82 (or typed-world "world")) =E2=94=82 (hello) =E2=94=82 ;; =3D> "world" =E2=94=82 (hello #:typed-world "typed") =E2=94=82 ;; =3D> "typed" =E2=94=82 (hello #:typed-world #t) =E2=94=82 ;; =3D> type error ~a ~a # #t =E2=94=82 ;; optional arguments =E2=94=82 (define-typed (hello #:optional typed-world) (string? #:optional = optional-string?) =E2=94=82 (or typed-world "world")) =E2=94=82 (hello) =E2=94=82 ;; =3D> "world" =E2=94=82 (hello "typed") =E2=94=82 ;; =3D> "typed" =E2=94=82 (hello #t) =E2=94=82 ;; =3D> type error ~a ~a # #t =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Best wishes, Arne --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQJEBAEBCAAuFiEE801qEjXQSQPNItXAE++NRSQDw+sFAmZD/WMQHGFybmVfYmFi QHdlYi5kZQAKCRAT741FJAPD6084D/9KQEBK3XxggLF87WNGUXzN8lW42+0W+z4/ BqZkdRwxSAiVpdvOJKjO8uxlDu6hHPSz4V0lsbqKgjGCewjPWdIK7mGWne3G49DI Mpin7E6fHz/MzMsPmOxp1F8jVtOrfkVyJrKeMMSm51oDqO5jLlGLRm8IljrmgD0T gNDv+OBOV1iczYqCRk2VL2qgrhqIkm6tsm0VApO7Yo1xw4YEdglx/d5baOk09txp r6YOymxjDAgE4jlqhEMIVsDEh62OHJasNEWA0Tk8Zgbreuk9u3+EL6AHWSJQIWeB XiLiYavJdo/2DCQAFf2MOp5LxV6+qUFsjfvbjKQafZaPqpm8RtaYHim3lcIqxgiK IlYHXas1O0Eh0y/tedWKpWoXtBj44uGQ0NugmR/sHw28V/Doil8vNEHPSELf5jL1 LXqbZ+jxTlwl+vPU/w2bUDJ6oZ8u9DOC8v7Hg/I0Gvfw8WqcGZzxmYs6JOjRvP8V 7ySGkIeBMG7R02BdaliG09Rmq/7CXxxroECxXcQVm1iiRmyAA1+11nGCxg6LPOh9 8saf/946lcOnQuhdwsC+63IIGU2qZp12ymSQsJvTfp2KxVUYHfw5JvgZGt/bVsQm Lfk8bZvvR3xgmCfcpCYtcjWU4gVe8u+oVkg+gOcwbZPsoM1h1xhi6zngG1L3txu5 6j0y1WJJ2ojEBAEBCAAuFiEE3Si95tmHXKvOSosd3M8NswvBBUgFAmZD/WMQHGFy bmVfYmFiQHdlYi5kZQAKCRDczw2zC8EFSOfpA/9SSZ9FfNC8d45Vj6h8U86SA0oO BNmETOnEo4HaP0ELNb3uaz29HmgGewiv7mxky0180tao6JV1G/aTlRHVnzMYByAR En1aZB63a/km6gKKizzq/oTdrDE1xPxFOE79SEwnhiomAmTTIROy2Tsum4sWRjes P0optjNwD/4lCChzMA== =GvR0 -----END PGP SIGNATURE----- --=-=-=--