From: "Linus Björnstam" <linus.internet@fastmail.se>
To: "Damien Mattei" <damien.mattei@gmail.com>,
guile-user <guile-user@gnu.org>
Cc: Jean-Paul Roy <jean-paul.roy@unice.fr>
Subject: Re: define anywhere
Date: Wed, 09 Jun 2021 12:11:21 +0200 [thread overview]
Message-ID: <a26ad4c7-e2d7-4389-ab95-ab08de8869de@www.fastmail.com> (raw)
In-Reply-To: <CADEOadeXFdQQBmKTsOiMnw6+ANqp7j4TcnSzbBCTqWPAiJJbHQ@mail.gmail.com>
Hi Damien!
The problem that define only defines a variable in the current lexical environment. Even if a definition in an if block would work from a syntactical standpoint, it would be pointless.
As per r6rs, internal (define ...) are akin to letrec, but are only allowed in definition context. Guile 3 relaxes this for function bodies, whereas the macros I linked above relaxes this for some additional forms. It cannot however "export" bindings to any outer environment.
What you can do is use module reflection to create top-level variables in the current module, but that makes everyone flinch about 105% of the time.
--
Linus Björnstam
On Wed, 9 Jun 2021, at 11:29, Damien Mattei wrote:
> hello, i'm just answering now because my ten years old Mac book pro
> definitely died sunday evening RIP
>
> i was trying to make macro that set! variable if they exist or create
> it before if the variable is not defined (tested by the Guile procedure
> 'defined?' which is not R*RS in any version)
>
> but it seems that Guile 3.0 'define' can not create variable in local
> blocks, as in Python :
> (if test
> (begin
> (define x 7)
> (foo x))
> (else-block))
> will not work.
>
> This behavior force the definition of all variable at the upper level
> of the function, the only advantage of guile 3.0 is perhaps (i have not
> tested it fully) that you can put define not only at beginning of
> function.
>
> This would be interesting to be able to define local variables with
> 'define',defining variable only in the block they are usefull.
>
> With those limitation in mind i defined a few more macros:
> (define-syntax <+
> (syntax-rules ()
> ((_ var expr) (define var expr))))
>
> { x <+ 7 } is equivalent to : (<- x 7) or (define x 7)
>
> := is the same as <+
> (define-syntax :=
> (syntax-rules ()
> ((_ var expr) (define var expr))))
>
> { x := 7 } is equivalent to : (:= x 7) or (define x 7)
>
> ;; definition without a value assigned
> ;; (def x)
> (define-syntax def
> (syntax-rules ()
> ((_ var) (define var '()))))
>
> i added all that to my previous macro system in my Scheme+
> (unfortunately my github account is on my dead mac,so no commit for now)
>
> i do not think i can do more for now, define anywhere in code could be
> a good solution to let letrec let* that in my opinion should no longer
> exist in Scheme.
>
> Here is an example on the famous sub set sum problem algorithm in two
> versions one with define 'anywhere' and the other with my previous
> macro of Scheme+:
> scheme@(guile-user)> (define L-init '(1 3 4 16 17 64 256 275 723 889
> 1040 1041 1093 1111 1284 1344 1520 2027 2734 3000 4285 5027))
> scheme@(guile-user)> (start-ssigma-sol-approx-pack-define-anywhere
> L-init 19836)
> $1 = (1 3 4 16 17 256 275 723 1040 1041 1284 1344 1520 3000 4285 5027)
> scheme@(guile-user)> (apply + '(1 3 4 16 17 256 275 723 1040 1041 1284
> 1344 1520 3000 4285 5027))
> $2 = 19836
>
> code:
> *Preview:*
>
> (define (start-ssigma-sol-approx-pack-define-anywhere L t) ;; Sub Set
> Sum problem (find solution or approximation)
> ;; { } are for infix notation as defined in SRFI 105
> ;; <+ and := are equivalent to (define var value)
> { best-sol <+ (lambda (L1 L2)
>
> {s1 <+ (apply + L1)}
> {s2 <+ (apply + L2)}
>
> (if {(abs {t - s1}) <= (abs {t - s2})}
> L1
> L2)) }
>
> ;; := is the same macro as <+
> { best-sol3 := (lambda (L1 L2 L3)
>
> {L22 <+ (best-sol L2 L3)}
> (best-sol L1 L22)) }
>
>
> { ssigma-sol-approx <+ (lambda (L)
> ;; def is a macro for declared but unasigned variable, it is same
> as (define var '())
> (def c)
> (def R)
>
> (if (null? L)
> L
> (begin {c <- (first L)}
> {R <- (rest L)}
>
> (cond [ {c = t} (list c) ] ;; c is the solution
> [ {c > t} (best-sol (list c) (ssigma-sol-approx R)) ] ;; c is
> to big to be a solution but could be an approximation
> ;; c < t at this point, 3 possibilities :
> ;; c is the best solution
> ;; c is part of the solution or his approximation
> ;; or c is not part of solution or his approximation
> [ else (best-sol3 (list c) ;; c is the best solution
>
> ;; c part of solution or is approximation
> (cons c (start-ssigma-sol-approx-pack-define-anywhere R {t
> - c})) ;; we have to find a solution or an approximation for t-c now
>
> ;; c is not part of solution or his approximation
> (ssigma-sol-approx R))])))) }
>
>
> ;; start the function
> (ssigma-sol-approx L))
> *
> *
>
> with other macros of Scheme+ code looked like this:*
> *
>
> *
> *
>
> *Preview:*
>
> ;; scheme@(guile-user)> (define L-init '(1 3 4 16 17 64 256 275 723 889
> 1040 1041 1093 1111 1284 1344 1520 2027 2734 3000 4285 5027))
> ;; scheme@(guile-user)> (start-ssigma-sol-approx-pack L-init 19836)
> ;; $1 = (1 3 4 16 17 256 275 723 1040 1041 1284 1344 1520 3000 4285
> 5027)
>
> (define (start-ssigma-sol-approx-pack L t) ;; Sub Set Sum problem (find
> solution or approximation)
>
>
> (letrec-arrow* [ best-sol ← (lambda (L1 L2)
>
> (let-arrow* [ s1 ← (apply + L1)
> s2 ← (apply + L2) ]
>
> (if {(abs {t - s1}) <= (abs {t - s2})}
> L1
> L2)))
>
> best-sol3 ← (lambda (L1 L2 L3)
>
> (let [(L22 (best-sol L2 L3))]
> (best-sol L1 L22)))
>
> ssigma-sol-approx ← (lambda (L)
>
> (if (null? L)
>
> L
>
> (let-arrow* [ c ← (first L)
> R ← (rest L) ]
>
> (cond [ {c = t} (list c) ] ;; c is the solution
> [ {c > t} (best-sol (list c) (ssigma-sol-approx R)) ] ;; c is
> to big to be a solution but could be an approximation
> ;; c < t at this point, 3 possibilities :
> ;; c is the best solution
> ;; c is part of the solution or his approximation
> ;; or c is not part of solution or his approximation
> [ else (best-sol3 (list c) ;; c is the best solution
>
> ;;(begin
> ;; (display "append c=") (display c) (newline)
> ;; c part of solution or is approximation
> (cons c (start-ssigma-sol-approx-pack R {t - c}));;) ;; we
> have to find a solution or an approximation for t-c now
>
> ;; c is not part of solution or his approximation
> (ssigma-sol-approx R))]))))
>
>
> ]
>
> ;; start the function
> (ssigma-sol-approx L)))
>
>
> the use of define anywhere will make code more readable, infixe
> notation and macros too...
>
> A last example in Scheme+ with arrays on the dynamic solution of subset
> sum problem (just answer if a solution exist or not):
>
> *Preview:*
>
> (include "../library-FunctProg/first-and-rest.scm")
> (include "../library-FunctProg/guile/array.scm")
> (include "../library-FunctProg/pair.scm")
> (include "../library-FunctProg/number.scm")
> (include "../library-FunctProg/list.scm")
> (include "../library-FunctProg/let.scm")
>
>
> (define L-init '(1 3 4 16 17 24 45 64 197 256 275 323 540 723 889 915
> 1040 1041 1093 1099 1111 1284 1344 1520 2027 2500 2734 3000 3267 3610
> 4285 5027))
>
> (define t-init 35267)
>
> (define ls (length L-init))
>
> (define dyna (make-array 0 {ls + 1} {t-init + 1}))
>
> (define (one-two b)
> (if b 1 2))
>
> (define cpt 0)
>
> ;; scheme@(guile-user)> (ssigma-dyna-define-anywhere L-init t-init)
> ;; $1 = #t
> ;; scheme@(guile-user)> cpt
> ;; $2 = 147801
> (define (ssigma-dyna-define-anywhere L t)
>
> {cpt <- {cpt + 1}} ;; cpt is defined at toplevel
>
> ;;(display L) (display " ") (display t) (newline)
>
> {ls <+ (length L)}
> {dyn <+ {dyna[ls t]}}
>
> (def c)
> (def R)
>
> ;; dyna[ls t] means 0: unknown solution, 1: solution found, 2: no solution
> (one?
> (if (not (zero? dyn))
>
> dyn
>
> ;; set the array but return the variable
> { dyna[ls t] <- (one-two
> (if (null? L)
> #f
> (begin
> {c <- (first L)}
> {R <- (rest L)}
> (cond [ {c = t} #t ] ;; c is the solution
> [ {c > t} (ssigma-dyna-define-anywhere R t) ] ;; c is to big
> to be a solution but can be an approximation
> ;; c < t at this point
> ;; c is part of the solution or his approximation
> ;; or c is not part of solution or his approximation
> [ else {(ssigma-dyna-define-anywhere R {t - c}) or
> (ssigma-dyna-define-anywhere R t)} ] )))) } )))
>
>
> Damien
>
>
> On Sun, Jun 6, 2021 at 7:32 PM Linus Björnstam
> <linus.internet@fastmail.se> wrote:
> > Try
> > ,expand (new-set! X 7) at the repl.
> >
> > That will however not do what you want. define does not work like that. Define adds the binding in what is called the current lexical environment: a define inside an if will not be visible outside that if (even if it would have been valid syntax).
> >
> > What are you trying to write?
> >
> > --
> > Linus Björnstam
> >
> > On Sun, 6 Jun 2021, at 17:16, Damien Mattei wrote:
> > > macros... i can not figure out how to make this one works:
> > > (define-syntax new-set!
> > > (syntax-rules ()
> > > ((_ var expr) (if (defined? (quote var))
> > > (set! var expr)
> > > (define var expr)))))
> > >
> > > scheme@(guile-user)> (new-set! x 7)
> > > ;;; <stdin>:24:0: warning: possibly unbound variable `x'
> > > ;;; <stdin>:24:0: warning: possibly unbound variable `x'
> > > ice-9/boot-9.scm:1669:16: In procedure raise-exception:
> > > Unbound variable: x
> > >
> > > Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.
> > > scheme@(guile-user) [1]> ,bt
> > > In current input:
> > > 24:0 1 (_)
> > > In ice-9/boot-9.scm:
> > > 1669:16 0 (raise-exception _ #:continuable? _)
> > >
> > > any idea?
> > >
> > > Damien
> > >
> > > On Sat, Jun 5, 2021 at 5:24 PM Linus Björnstam
> > > <linus.internet@fastmail.se> wrote:
> > > > I implemented this hack before guile 3 got defines in function bodies: https://hg.sr.ht/~bjoli/guile-define
> > > >
> > > > Even I guile 3 it allows a more liberal placement of define, but it won't work for things like bodies of imported macros (like match)
> > > > --
> > > > Linus Björnstam
> > > >
> > > > On Sat, 5 Jun 2021, at 00:27, Damien Mattei wrote:
> > > > > hello,
> > > > > i'm was considering that i want to be able to define a variable
> > > > > anywhere in
> > > > > code, the way Python do. Few scheme can do that (Bigloo i know)
> > > > > ( the list here is not exact:
> > > > > https://www.reddit.com/r/scheme/comments/b73fdz/placement_of_define_inside_lambda_bodies_in/
> > > > > )
> > > > > is it possible in guile to do it? i do not know, so could it be added
> > > > > to
> > > > > the language specification for future release?
> > > > >
> > > > > regards,
> > > > > Damien
> > > > >
next prev parent reply other threads:[~2021-06-09 10:11 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-04 22:27 define anywhere Damien Mattei
2021-06-05 2:10 ` Taylan Kammer
2021-06-05 8:50 ` Dr. Arne Babenhauserheide
2021-06-05 15:23 ` Linus Björnstam
2021-06-06 8:09 ` Linus Björnstam
2021-06-06 12:02 ` Dr. Arne Babenhauserheide
2021-06-06 13:36 ` Linus Björnstam
2021-06-06 16:45 ` Dr. Arne Babenhauserheide
2021-06-11 8:08 ` Damien Mattei
[not found] ` <CADEOadcwk1D9of6C1owQQSqFNRvUmA=wJKSngySbGsfdDUzoMw@mail.gmail.com>
[not found] ` <28842df5-d82b-4819-b7ad-2148265f7a83@www.fastmail.com>
2021-06-09 9:29 ` Damien Mattei
2021-06-09 10:11 ` Linus Björnstam [this message]
2021-06-11 8:15 ` Damien Mattei
2021-06-11 8:07 ` Damien Mattei
2021-06-11 23:43 ` Damien Mattei
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a26ad4c7-e2d7-4389-ab95-ab08de8869de@www.fastmail.com \
--to=linus.internet@fastmail.se \
--cc=damien.mattei@gmail.com \
--cc=guile-user@gnu.org \
--cc=jean-paul.roy@unice.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).