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