[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: define anywhere
From: |
Linus Björnstam |
Subject: |
Re: define anywhere |
Date: |
Wed, 09 Jun 2021 12:11:21 +0200 |
User-agent: |
Cyrus-JMAP/3.5.0-alpha0-519-g27a961944e-fm-20210531.001-g27a96194 |
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
> > > > >