unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* escaping from a recursive call
@ 2022-11-09 15:56 Damien Mattei
  2022-11-09 16:51 ` Olivier Dion via General Guile related discussions
  0 siblings, 1 reply; 13+ messages in thread
From: Damien Mattei @ 2022-11-09 15:56 UTC (permalink / raw)
  To: guile-user

i need a way to escape not only the current call of a recursive function
(it is already done) but alls:

example:

(def (foo n)
     (cond ((= n 0) 'end0)
  ((= n 7) (return 'end7))
  (else (cons n (foo {n - 1})))))

cheme@(guile-user)> (foo 5)
(5 4 3 2 1 . end0)
scheme@(guile-user)> (foo 10)
(10 9 8 . end7)

it has just escaped from the current call to foo

(def (bar n)
     (cond ((= n 0) 'end0)
  ((= n 7) (return-rec 'end7))
  (else (cons n (bar {n - 1})))))

scheme@(guile-user)> (bar 5)
(5 4 3 2 1 . end0)
scheme@(guile-user)> (bar 10)
ice-9/boot-9.scm:1669:16: In procedure raise-exception:
Unbound variable: return-rec

i admit i should read the K. Dybvig macro paper but still had not
completely do it.

i modify this code of my Scheme+ but it fails on (bar 10) :

(define-syntax def

  (lambda (stx)

      (syntax-case stx ()

;; multiple definitions without values assigned
;; (def (x y z))
((_ (var1 ...)) #`(begin (define var1 '()) ...))

;;  (def (foo) (when #t (return "hello") "bye"))
        ;; ((_ (<name> <arg> ...) <body> <body>* ...)
        ;;  (let ((ret-id (datum->syntax stx 'return)))
        ;;    #`(define (<name> <arg> ...)
;;        (call/cc (lambda (#,ret-id) <body> <body>* ...)))))

((_ (<name> <arg> ...) <body> <body>* ...)

         (let ((ret-id (datum->syntax stx 'return))
      (ret-rec-id (datum->syntax stx 'return-rec)))

  #`(define (<name> <arg> ...)


      (define (<name> <arg> ...)
(call/cc (lambda (#,ret-id) <body> <body>* ...)))

      (call/cc (lambda (#,ret-rec-id)
 (<name> <arg> ...))))))

;; single definition without a value assigned
;; (def x)
((_ var) #`(define var '()))

;; (def x 7)
((_ var expr) #`(define var expr))

((_ err ...) #`(syntax-error "Bad def form"))

)))

i'am even surprised it works on (bar 5)

if someone had a solution to this problem i will again copy/paste it in my
code and gracefully thanks him a lot :-)

best regards,
damien


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 15:56 escaping from a recursive call Damien Mattei
@ 2022-11-09 16:51 ` Olivier Dion via General Guile related discussions
  2022-11-09 17:18   ` Damien Mattei
  0 siblings, 1 reply; 13+ messages in thread
From: Olivier Dion via General Guile related discussions @ 2022-11-09 16:51 UTC (permalink / raw)
  To: Damien Mattei, guile-user

On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> i need a way to escape not only the current call of a recursive function
> (it is already done) but alls:
>
> example:
>
> (def (foo n)
>      (cond ((= n 0) 'end0)
>   ((= n 7) (return 'end7))
>   (else (cons n (foo {n - 1})))))

Is that what you want?
--8<---------------cut here---------------start------------->8---
(use-modules
 (ice-9 control))

(define (foo n)
  (let/ec return
    (let loop ((n n))
      (cond
       ((= n 0) 'end0)
       ((= n 7) (return 'end7))
       (else
        (cons n (loop (1- n))))))))

(pk (foo 5))
(pk (foo 10))
--8<---------------cut here---------------end--------------->8---

-- 
Olivier Dion
oldiob.dev



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 16:51 ` Olivier Dion via General Guile related discussions
@ 2022-11-09 17:18   ` Damien Mattei
  2022-11-09 17:55     ` Olivier Dion via General Guile related discussions
  2022-11-09 18:56     ` Zelphir Kaltstahl
  0 siblings, 2 replies; 13+ messages in thread
From: Damien Mattei @ 2022-11-09 17:18 UTC (permalink / raw)
  To: guile-user

but in the general case  , i want a macro that can do it on any function
(i'm not sure it can be done because the continuation have to be captured
just before the call to the function and be inlined at the good place....)

On Wed, Nov 9, 2022 at 5:52 PM Olivier Dion <olivier.dion@polymtl.ca> wrote:

> On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > i need a way to escape not only the current call of a recursive function
> > (it is already done) but alls:
> >
> > example:
> >
> > (def (foo n)
> >      (cond ((= n 0) 'end0)
> >   ((= n 7) (return 'end7))
> >   (else (cons n (foo {n - 1})))))
>
> Is that what you want?
> --8<---------------cut here---------------start------------->8---
> (use-modules
>  (ice-9 control))
>
> (define (foo n)
>   (let/ec return
>     (let loop ((n n))
>       (cond
>        ((= n 0) 'end0)
>        ((= n 7) (return 'end7))
>        (else
>         (cons n (loop (1- n))))))))
>
> (pk (foo 5))
> (pk (foo 10))
> --8<---------------cut here---------------end--------------->8---
>
> --
> Olivier Dion
> oldiob.dev
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 17:18   ` Damien Mattei
@ 2022-11-09 17:55     ` Olivier Dion via General Guile related discussions
  2022-11-09 18:49       ` Damien Mattei
  2022-11-10 12:32       ` Chris Vine
  2022-11-09 18:56     ` Zelphir Kaltstahl
  1 sibling, 2 replies; 13+ messages in thread
From: Olivier Dion via General Guile related discussions @ 2022-11-09 17:55 UTC (permalink / raw)
  To: Damien Mattei, guile-user

On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> but in the general case  , i want a macro that can do it on any function
> (i'm not sure it can be done because the continuation have to be captured
> just before the call to the function and be inlined at the good
> place....)

I'm not aware of any control mechanism that are implicit in Guile.  You
almost always have to deal with a continuation object.  However, nothing
prevent you to invent your own control flow wrapper.

For example:
--8<---------------cut here---------------start------------->8---
(define my-prompt (make-prompt-tag))

(define-syntax-rule (return-now x)
  (abort-to-prompt my-prompt x))

(define (wrap-this procedure)
  (let ((inside? #f))
    (lambda args
      (if inside?
          (apply procedure args)
          (begin
            (set! inside? #t)
            (let ((ret
                   (call-with-prompt my-prompt
                     (lambda ()
                       (apply procedure args))
                     (lambda (_ x)
                       x))))
              (set! inside? #f)
              ret))))))

(define-syntax define-interruptible
  (syntax-rules ()
    ((_ (name formals ...) body ...)
     (define name
       (wrap-this
        (lambda (formals ...) body ...))))))

(define-interruptible (foo n)
  (cond
   ((= n 0) 'end0)
   ((= n 7) (return-now 'end7))
   (else
    (cons n (foo (1- n))))))

(pk (foo 5))
(pk (foo 10))
--8<---------------cut here---------------end--------------->8---

There's probably other way of doing so that I'm not aware of.

-- 
Olivier Dion
oldiob.dev



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 17:55     ` Olivier Dion via General Guile related discussions
@ 2022-11-09 18:49       ` Damien Mattei
  2022-11-10  1:20         ` Olivier Dion via General Guile related discussions
  2022-11-10 12:32       ` Chris Vine
  1 sibling, 1 reply; 13+ messages in thread
From: Damien Mattei @ 2022-11-09 18:49 UTC (permalink / raw)
  To: Olivier Dion; +Cc: guile-user

good... thank, it works, i do not know a lot about 'prompts , a good
explanation is here:

https://stackoverflow.com/questions/29838344/what-exactly-is-a-continuation-prompt

i personally find a solution too:

(define-syntax def

  (lambda (stx)

      (syntax-case stx ()

;; multiple definitions without values assigned
;; (def (x y z))
((_ (var1 ...)) #`(begin (define var1 '()) ...))

;;  (def (foo) (when #t (return "hello") "bye"))
        ;; ((_ (<name> <arg> ...) <body> <body>* ...)
        ;;  (let ((ret-id (datum->syntax stx 'return)))
        ;;    #`(define (<name> <arg> ...)
;;        (call/cc (lambda (#,ret-id) <body> <body>* ...)))))

((_ (<name> <arg>  ...) <body> <body>* ...)

         (let ((ret-id (datum->syntax stx 'return))
      (ret-rec-id (datum->syntax stx 'return-rec)))

  #`(define (<name> <arg> ...)

      (call/cc (lambda (#,ret-rec-id)

(apply (rec <name> (lambda (<arg> ...)
     (call/cc (lambda (#,ret-id) <body> <body>* ...)))) (list <arg>
...)))))))

;; single definition without a value assigned
;; (def x)
((_ var) #`(define var '()))

;; (def x 7)
((_ var expr) #`(define var expr))

((_ err ...) #`(syntax-error "Bad def form"))

)))

example:
;; scheme@(guile-user)> (foo 5)
;; $2 = (5 4 3 2 1 . end0)
;; scheme@(guile-user)> (foo 10)
;; $3 = (10 9 8 . end7)
;; scheme@(guile-user)> (bar 5)
;; $4 = (5 4 3 2 1 . end0)
;; scheme@(guile-user)> (bar 10)
;; $5 = end7

(def (foo n)
     (cond ((= n 0) 'end0)
  ((= n 7) (return 'end7))
  (else (cons n (foo {n - 1})))))


(def (bar n)
     (cond ((= n 0) 'end0)
  ((= n 7) (return-rec 'end7))
  (else (cons n (bar {n - 1})))))

the important part of this macro being:

((_ (<name> <arg> ...) <body> <body>* ...)

         (let ((ret-id (datum->syntax stx 'return))
      (ret-rec-id (datum->syntax stx 'return-rec)))

  #`(define (<name> <arg> ...)

      (call/cc (lambda (#,ret-rec-id)

(apply (rec <name> (lambda (<arg> ...)
     (call/cc (lambda (#,ret-id) <body> <body>* ...)))) (list <arg>
...)))))))

but i admit i had a chance to find this solution, i did it  a bit like a
blind man...

but after all:

“A mathematician is a blind man in a dark room looking for a black cat
which isn’t there.”

-- Charles Darwin

Best regards,

Damien

On Wed, Nov 9, 2022 at 6:55 PM Olivier Dion <olivier.dion@polymtl.ca> wrote:

> On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > but in the general case  , i want a macro that can do it on any function
> > (i'm not sure it can be done because the continuation have to be captured
> > just before the call to the function and be inlined at the good
> > place....)
>
> I'm not aware of any control mechanism that are implicit in Guile.  You
> almost always have to deal with a continuation object.  However, nothing
> prevent you to invent your own control flow wrapper.
>
> For example:
> --8<---------------cut here---------------start------------->8---
> (define my-prompt (make-prompt-tag))
>
> (define-syntax-rule (return-now x)
>   (abort-to-prompt my-prompt x))
>
> (define (wrap-this procedure)
>   (let ((inside? #f))
>     (lambda args
>       (if inside?
>           (apply procedure args)
>           (begin
>             (set! inside? #t)
>             (let ((ret
>                    (call-with-prompt my-prompt
>                      (lambda ()
>                        (apply procedure args))
>                      (lambda (_ x)
>                        x))))
>               (set! inside? #f)
>               ret))))))
>
> (define-syntax define-interruptible
>   (syntax-rules ()
>     ((_ (name formals ...) body ...)
>      (define name
>        (wrap-this
>         (lambda (formals ...) body ...))))))
>
> (define-interruptible (foo n)
>   (cond
>    ((= n 0) 'end0)
>    ((= n 7) (return-now 'end7))
>    (else
>     (cons n (foo (1- n))))))
>
> (pk (foo 5))
> (pk (foo 10))
> --8<---------------cut here---------------end--------------->8---
>
> There's probably other way of doing so that I'm not aware of.
>
> --
> Olivier Dion
> oldiob.dev
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 17:18   ` Damien Mattei
  2022-11-09 17:55     ` Olivier Dion via General Guile related discussions
@ 2022-11-09 18:56     ` Zelphir Kaltstahl
  1 sibling, 0 replies; 13+ messages in thread
From: Zelphir Kaltstahl @ 2022-11-09 18:56 UTC (permalink / raw)
  To: Damien Mattei; +Cc: guile-user

Hello Damien,

On 11/9/22 18:18, Damien Mattei wrote:
> but in the general case  , i want a macro that can do it on any function
> (i'm not sure it can be done because the continuation have to be captured
> just before the call to the function and be inlined at the good place....)
>
> On Wed, Nov 9, 2022 at 5:52 PM Olivier Dion<olivier.dion@polymtl.ca>  wrote:
>
>> On Wed, 09 Nov 2022, Damien Mattei<damien.mattei@gmail.com>  wrote:
>>> i need a way to escape not only the current call of a recursive function
>>> (it is already done) but alls:
>>>
>>> example:
>>>
>>> (def (foo n)
>>>       (cond ((= n 0) 'end0)
>>>    ((= n 7) (return 'end7))
>>>    (else (cons n (foo {n - 1})))))
>> Is that what you want?
>> --8<---------------cut here---------------start------------->8---
>> (use-modules
>>   (ice-9 control))
>>
>> (define (foo n)
>>    (let/ec return
>>      (let loop ((n n))
>>        (cond
>>         ((= n 0) 'end0)
>>         ((= n 7) (return 'end7))
>>         (else
>>          (cons n (loop (1- n))))))))
>>
>> (pk (foo 5))
>> (pk (foo 10))
>> --8<---------------cut here---------------end--------------->8---
>>
>> --
>> Olivier Dion
>> oldiob.dev

Another thing you could do is to pass the continuation to the function you are 
calling explicitly. I built a small example, which is not really a real-world 
use-case, but hopefully explains the idea:

~~~~
(import (except (rnrs base))
         (only (guile)
               lambda* λ
               display
               simple-format))


(define factorial-with-continuation
   (lambda* (n
             #:optional
             ;; Explicitly specifying an argument, which is a
             ;; continuation.
             ;; By default the continuation cont is merely
             ;; returning the value given. Identity
             ;; function. Not doing anything with the result.
             (cont (λ (x) x))
             ;; Using `remainder` only as an example.
             (test (λ (num) (= (remainder num 7) 0))))
     (let iter ([num° (- n 1)]
                [product° n])
       (cond
        ;; Base case of factorial.
        [(<= num° 1) product°]
        ;; Next a case with some condition, which, if true
        ;; means you want to exit.
        [(test num°)
         (cont product°)]
        ;; Otherwise normal iteration.
        [else
         (iter (- num° 1)
               (* product° num°))]))))


(factorial-with-continuation 10)
(factorial-with-continuation 10
                              ;; A continuation, which merely
                              ;; display something, but then
                              ;; returns the value.
                              (λ (num)
                                (display (simple-format #f "~a\n" num))
                                num)
                              ;; Another weird condition.
                              (λ (num) (= (remainder num 17) 0)))
~~~~

In this case the continuation only displays something, but you could make it do 
whatever you want, including using its result inside the function you are 
calling, instead of returning it. Also you can define the continuation before 
calling the function `factorial-with-continuation`.

This might not be the most convenient way, since you have an additional 
argument, but maybe it is a very general way of doing something like that.

Regards,
Zelphir

-- 
repositories:https://notabug.org/ZelphirKaltstahl


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 18:49       ` Damien Mattei
@ 2022-11-10  1:20         ` Olivier Dion via General Guile related discussions
  2022-11-10  4:56           ` tomas
  2022-11-10  5:25           ` Damien Mattei
  0 siblings, 2 replies; 13+ messages in thread
From: Olivier Dion via General Guile related discussions @ 2022-11-10  1:20 UTC (permalink / raw)
  To: Damien Mattei; +Cc: guile-user

On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> good... thank, it works, i do not know a lot about 'prompts , a good
> explanation is here:
>
> https://stackoverflow.com/questions/29838344/what-exactly-is-a-continuation-prompt

In the Guile manual:

Top > API Reference > Control Mechanisms > Prompts

or here <https://www.gnu.org/software/guile/manual/html_node/Prompts.html>.

-- 
Olivier Dion
oldiob.dev



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-10  1:20         ` Olivier Dion via General Guile related discussions
@ 2022-11-10  4:56           ` tomas
  2022-11-10  6:01             ` Damien Mattei
  2022-11-10  5:25           ` Damien Mattei
  1 sibling, 1 reply; 13+ messages in thread
From: tomas @ 2022-11-10  4:56 UTC (permalink / raw)
  To: guile-user

[-- Attachment #1: Type: text/plain, Size: 674 bytes --]

On Wed, Nov 09, 2022 at 08:20:31PM -0500, Olivier Dion via General Guile related discussions wrote:
> On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > good... thank, it works, i do not know a lot about 'prompts , a good
> > explanation is here:
> >
> > https://stackoverflow.com/questions/29838344/what-exactly-is-a-continuation-prompt
> 
> In the Guile manual:
> 
> Top > API Reference > Control Mechanisms > Prompts
> 
> or here <https://www.gnu.org/software/guile/manual/html_node/Prompts.html>.

And then, of course, Andy's write-up:

  https://wingolog.org/archives/2010/02/26/guile-and-delimited-continuations

Cheers
-- 
t 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-10  1:20         ` Olivier Dion via General Guile related discussions
  2022-11-10  4:56           ` tomas
@ 2022-11-10  5:25           ` Damien Mattei
  2022-11-10 17:03             ` Olivier Dion via General Guile related discussions
  1 sibling, 1 reply; 13+ messages in thread
From: Damien Mattei @ 2022-11-10  5:25 UTC (permalink / raw)
  To: Olivier Dion, Zelphir Kaltstahl; +Cc: guile-user

yes Olivier, i had found the Guile doc and i was asking myself, but the doc
is quite "succint" without a lot of explanation and i'm asking if it exists
more documentation and if it is or will be standardised in any R?RS...  and
i'm asking too how can it be integrated in my macro 'def to be used in any
procedure definition...
it is like the solution of Zephir, i do not want to explicitly pass the
continuation to the function , i wanted a schema that allow to capture the
continuation exactly before the initial function call (not at function
definition, not at the current level of recursion,my previous 'def macro
already do that ...) and that was not so easy, i'm glad of this solution
(that provide 'return for the current level of recursion and 'return-rec to
escape all the recursive calls), but i admit i find it more by intuition
than logic and i'm asking if it will work in any situation i will
encounter? see the example below that motivate my research...
will it work well in // code with future or thread ,i'm having already
problem with // code that,compute well but show no speed up, is it because
of continuation? not being compatible with //,does macro generates
functions that causes unknown problem to // code, i try to get rid of
macros and continuation in // code but i always fall back using them...

i was in need of a way to escape the recursive call in a function
that unify two minterms.
Minterms (example: 0100101) are represented by lists : (0 1 0 0 1 0 1)
,they have weight , the weight is the # cardinal of ones in the minterm
,for example the minterm 0100101 has a weight of 3.
We must only unify minterms of a weight difference of one.
The result of unify 2 minterms of different weight is to replace the  (if
only one) differents bits by 'x , example:
(0 1 0 1) and (0 0 0 1) are unified with result of : (0 x 0 1)
if there is more than 2 differents bits ,giving more than 1 'x in the
result it is false,also if minterms have different lengths.
Recursively we can unify the results , example (0 x 0 1) and (0 x 1 1) are
unified with result of (0 x x 1) ,etc...

my initial function to do that was:
(define (unify-two-minterms mt1 mt2)
  (function-map-with-escaping-by-kontinuation2
 (macro-function-compare-2-bits-with-continuation) mt1 mt2))

but since i have problem with // speed up i try other procedure:
below you see the need of having to sort of escape ,'return from the
current level in case of end of lists,and 'return-rec from the full stack
of recursions in cas of #f result.

(define (unify-two-minterms-rec mt1 mt2)

  {err <+ #f}

  (def (unify-two-lists-tolerant-one-mismatch mt1 mt2)

       (if {(null? mt1) and (null? mt2)}
	   (return '()))

       (if {{(null? mt1) and (not (null? mt2))} or {(not (null? mt1))
and (null? mt2)}}
	   (return-rec #f))
	

       {fst-mt1 <+ (first mt1)}
       {fst-mt2 <+ (first mt2)}

       (if (equal? fst-mt1 fst-mt2) (return (cons fst-mt1
						  (unify-two-lists-tolerant-one-mismatch (rest mt1) (rest mt2)))))
       (if err (return-rec #f))

       {err <- #t}
       (cons 'x
	     (unify-two-lists-tolerant-one-mismatch (rest mt1) (rest mt2))))

  (unify-two-lists-tolerant-one-mismatch mt1 mt2))


https://github.com/damien-mattei/library-FunctProg/blob/master/guile/logiki%2B.scm#L2805

scheme@(guile-user)>  (unify-two-minterms-rec '(1 0 1 0 0 1 0 1 0 1) '(1 1
1 0 1 0 0 1 0 1))
$1 = #f
scheme@(guile-user)> (unify-two-minterms-rec '(1 0 1 0 0 1 0 1 0 1) '(1 0 1
0 1 1 0 1 0 1))
$2 = (1 0 1 0 x 1 0 1 0 1)

i have tested but still no speed up with 'futures, i have test it with
Guile but the same problem is with Racket. Seems 'furure makes no speed up
, it is hard to share the benchmarks now that i have updated the 'def of
Scheme+ but i  then i have to release a new version and update all the
github and documentation online.Soon i hope...

Damien


On Thu, Nov 10, 2022 at 2:20 AM Olivier Dion <olivier.dion@polymtl.ca>
wrote:

> On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > good... thank, it works, i do not know a lot about 'prompts , a good
> > explanation is here:
> >
> >
> https://stackoverflow.com/questions/29838344/what-exactly-is-a-continuation-prompt
>
> In the Guile manual:
>
> Top > API Reference > Control Mechanisms > Prompts
>
> or here <https://www.gnu.org/software/guile/manual/html_node/Prompts.html
> >.
>
> --
> Olivier Dion
> oldiob.dev
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-10  4:56           ` tomas
@ 2022-11-10  6:01             ` Damien Mattei
  0 siblings, 0 replies; 13+ messages in thread
From: Damien Mattei @ 2022-11-10  6:01 UTC (permalink / raw)
  To: tomas; +Cc: guile-user

oui bonne illustration du probléme...
yes good explanation of problem...
it's not simple, hope my macro is ok, for now all my code compile and run
the same way ! :-) (but still no speed up :-( )
merçi
Damien

On Thu, Nov 10, 2022 at 5:57 AM <tomas@tuxteam.de> wrote:

> On Wed, Nov 09, 2022 at 08:20:31PM -0500, Olivier Dion via General Guile
> related discussions wrote:
> > On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > > good... thank, it works, i do not know a lot about 'prompts , a good
> > > explanation is here:
> > >
> > >
> https://stackoverflow.com/questions/29838344/what-exactly-is-a-continuation-prompt
> >
> > In the Guile manual:
> >
> > Top > API Reference > Control Mechanisms > Prompts
> >
> > or here <
> https://www.gnu.org/software/guile/manual/html_node/Prompts.html>.
>
> And then, of course, Andy's write-up:
>
>
> https://wingolog.org/archives/2010/02/26/guile-and-delimited-continuations
>
> Cheers
> --
> t
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-09 17:55     ` Olivier Dion via General Guile related discussions
  2022-11-09 18:49       ` Damien Mattei
@ 2022-11-10 12:32       ` Chris Vine
  2022-11-10 13:48         ` Damien Mattei
  1 sibling, 1 reply; 13+ messages in thread
From: Chris Vine @ 2022-11-10 12:32 UTC (permalink / raw)
  To: guile-user

On Wed, 09 Nov 2022 12:55:42 -0500
Olivier Dion via General Guile related discussions <guile-user@gnu.org>
wrote:
> On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > but in the general case  , i want a macro that can do it on any function
> > (i'm not sure it can be done because the continuation have to be captured
> > just before the call to the function and be inlined at the good
> > place....)
> 
> I'm not aware of any control mechanism that are implicit in Guile.  You
> almost always have to deal with a continuation object.  However, nothing
> prevent you to invent your own control flow wrapper.

You can construct an anaphoric macro with that in mind.  This introduces
an imperative-style 'loop' macro which carries within the loop block a
'break' keyword which will cause the loop to exit:

  (use-modules (ice-9 control)) ;; for call/ec

  (define-syntax loop
    (lambda (x)
      (syntax-case x ()
        [(k e ...)
         (with-syntax ([break (datum->syntax #'k 'break)])
	   #'(call/ec
	      (lambda (break)
	        (let f () e ... (f)))))])))

  (display (let ([n 3] [lst '()])
             (loop
              (if (= n 0) (break lst))
              (set! lst (cons 'a lst))
              (set! n (- n 1)))))
  (newline)

However explicit control of loops is better in my view.  Imperative
loops usually end up with mutable bindings, as in the example above.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-10 12:32       ` Chris Vine
@ 2022-11-10 13:48         ` Damien Mattei
  0 siblings, 0 replies; 13+ messages in thread
From: Damien Mattei @ 2022-11-10 13:48 UTC (permalink / raw)
  To: guile-user

solutions have been posted, i'm using mine, which update my 'def macro:

;; (def (bar n);;      (cond ((= n 0) 'end0);; 	   ((= n 7)
(return-rec 'end7));; 	   (else (cons n (bar {n - 1})))))
;; scheme@(guile-user)> (bar 5);; $4 = (5 4 3 2 1 . end0);;
scheme@(guile-user)> (bar 10);; $5 = end7
(define-syntax def

  (lambda (stx)

      (syntax-case stx ()

	;; multiple definitions without values assigned
	;; (def (x y z))
	((_ (var1 ...)) #`(begin (define var1 '()) ...))
	
	;;  (def (foo) (when #t (return "hello") "bye"))
        ;; ((_ (<name> <arg> ...) <body> <body>* ...)
        ;;  (let ((ret-id (datum->syntax stx 'return)))
        ;;    #`(define (<name> <arg> ...)
	;;        (call/cc (lambda (#,ret-id) <body> <body>* ...)))))

	
	((_ (<name> <arg> ...) <body> <body>* ...)
	
         (let ((ret-id (datum->syntax stx 'return))
	       (ret-rec-id (datum->syntax stx 'return-rec)))

	   #`(define (<name> <arg> ...)

	       (call/cc (lambda (#,ret-rec-id)
			
			 (apply (rec <name> (lambda (<arg> ...)
					      (call/cc (lambda (#,ret-id) <body> <body>* ...)))) (list
<arg> ...)))))))

	

	
	;; single definition without a value assigned
	;; (def x)
	((_ var) #`(define var '()))

	;; (def x 7)
	((_ var expr) #`(define var expr))

	((_ err ...) #`(syntax-error "Bad def form"))

	)))


i have tested it with my code and it works well,for now.
Also i can not notice any slowing of the code and that is important ad 'def
is a replacement often used in my projects now.
I will update my Scheme+ with it soon, when i have time.
Regards,
Damien


On Thu, Nov 10, 2022 at 1:33 PM Chris Vine <vine.chris@gmail.com> wrote:

> On Wed, 09 Nov 2022 12:55:42 -0500
> Olivier Dion via General Guile related discussions <guile-user@gnu.org>
> wrote:
> > On Wed, 09 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> > > but in the general case  , i want a macro that can do it on any
> function
> > > (i'm not sure it can be done because the continuation have to be
> captured
> > > just before the call to the function and be inlined at the good
> > > place....)
> >
> > I'm not aware of any control mechanism that are implicit in Guile.  You
> > almost always have to deal with a continuation object.  However, nothing
> > prevent you to invent your own control flow wrapper.
>
> You can construct an anaphoric macro with that in mind.  This introduces
> an imperative-style 'loop' macro which carries within the loop block a
> 'break' keyword which will cause the loop to exit:
>
>   (use-modules (ice-9 control)) ;; for call/ec
>
>   (define-syntax loop
>     (lambda (x)
>       (syntax-case x ()
>         [(k e ...)
>          (with-syntax ([break (datum->syntax #'k 'break)])
>            #'(call/ec
>               (lambda (break)
>                 (let f () e ... (f)))))])))
>
>   (display (let ([n 3] [lst '()])
>              (loop
>               (if (= n 0) (break lst))
>               (set! lst (cons 'a lst))
>               (set! n (- n 1)))))
>   (newline)
>
> However explicit control of loops is better in my view.  Imperative
> loops usually end up with mutable bindings, as in the example above.
>
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: escaping from a recursive call
  2022-11-10  5:25           ` Damien Mattei
@ 2022-11-10 17:03             ` Olivier Dion via General Guile related discussions
  0 siblings, 0 replies; 13+ messages in thread
From: Olivier Dion via General Guile related discussions @ 2022-11-10 17:03 UTC (permalink / raw)
  To: Damien Mattei, Zelphir Kaltstahl; +Cc: guile-user

On Thu, 10 Nov 2022, Damien Mattei <damien.mattei@gmail.com> wrote:
> will it work well in // code with future or thread ,i'm having already
> problem with // code that,compute well but show no speed up, is it because
> of continuation? not being compatible with //,does macro generates
> functions that causes unknown problem to // code, i try to get rid of
> macros and continuation in // code but i always fall back using
> them...

There's many problem that arise when you play with continuation in
multi-threads environment.  See the scheduler of my library
guile-parallel <https://sr.ht/~old/guile-parallel/> for example.

> but since i have problem with // speed up i try other procedure:
> below you see the need of having to sort of escape ,'return from the
> current level in case of end of lists,and 'return-rec from the full stack
> of recursions in cas of #f result.

>
> (define (unify-two-minterms-rec mt1 mt2)
>
>   {err <+ #f}
>
>   (def (unify-two-lists-tolerant-one-mismatch mt1 mt2)
>
>        (if {(null? mt1) and (null? mt2)}
> 	   (return '()))
>
>        (if {{(null? mt1) and (not (null? mt2))} or {(not (null? mt1))
> and (null? mt2)}}
> 	   (return-rec #f))
> 	
>
>        {fst-mt1 <+ (first mt1)}
>        {fst-mt2 <+ (first mt2)}
>
>        (if (equal? fst-mt1 fst-mt2) (return (cons fst-mt1
> 						  (unify-two-lists-tolerant-one-mismatch (rest mt1) (rest mt2)))))
>        (if err (return-rec #f))
>
>        {err <- #t}
>        (cons 'x
> 	     (unify-two-lists-tolerant-one-mismatch (rest mt1) (rest mt2))))
>
>   (unify-two-lists-tolerant-one-mismatch mt1 mt2))

If you make your algorithm tail recursive, you should be able to espace
from any level of recursion without penalty. From what I've read here,
your algorithm is not tail recursive and so a frame is made a each level
of recursion, requiring an unwinding of it after.  Keep in mind that
delimited continuation are not free.  It's kind of like a userspace
context switching.  It involves memory load/store and stack unwinding,
probably also other implementation dependant details in the runtime.  I
would not advice to use them in critical performant scenario nor in
parallelized algorithm.

> i have tested but still no speed up with 'futures, i have test it with
> Guile but the same problem is with Racket. Seems 'furure makes no speed up
> , it is hard to share the benchmarks now that i have updated the 'def of
> Scheme+ but i  then i have to release a new version and update all the
> github and documentation online.Soon i hope...

I haven't tackle your minterm problem directly here, but from a glimpse
of it, I don't see which part can be parallelize?  Furthermore, you have
a global state `err` that will impose penalty for sure.  Maybe doing a
divide and conquer approach?  In that case I would highly recommend
using vector instead of list, but you would still have problem with the
global state that should be an atomic box.

-- 
Olivier Dion
oldiob.dev



^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-11-10 17:03 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-09 15:56 escaping from a recursive call Damien Mattei
2022-11-09 16:51 ` Olivier Dion via General Guile related discussions
2022-11-09 17:18   ` Damien Mattei
2022-11-09 17:55     ` Olivier Dion via General Guile related discussions
2022-11-09 18:49       ` Damien Mattei
2022-11-10  1:20         ` Olivier Dion via General Guile related discussions
2022-11-10  4:56           ` tomas
2022-11-10  6:01             ` Damien Mattei
2022-11-10  5:25           ` Damien Mattei
2022-11-10 17:03             ` Olivier Dion via General Guile related discussions
2022-11-10 12:32       ` Chris Vine
2022-11-10 13:48         ` Damien Mattei
2022-11-09 18:56     ` Zelphir Kaltstahl

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).