thank Taylan i already use all that in the past ( https://github.com/damien-mattei/library-FunctProg/blob/master/syntactic-sugar.scm#L133 ) but it was late ,past 1h00 and i forget it, and it was not compatible with R5RS thank for your long and clear explainations... i did not use let/ec because the problem was not with let/ec or call/cc but with the macro hygiene and i wanted to stay compatible with other scheme,let/ec should be guile only and i suppose let/ec made with call/cc . regards, damien
On Mon, Jun 28, 2021 at 3:15 AM Taylan Kammer <taylan.kam...@gmail.com> wrote: > On 28.06.2021 01:10, Damien Mattei wrote: > > hi, > > > > i wanted to create a macro that is used like a function definition and > > allow return using call/cc: > > > > (define-syntax def > > (syntax-rules (return) > > ((_ (name args ...) body body* ...) > > (define name (lambda (args ...) > > (call/cc (lambda (return) body body* ...))))) > > ((_ name expr) (define name expr)))) > > > > unfortunaly i got error: > > > > scheme@(guile-user)> (def (test x) (cond ((= x 3) 7) ((= x 2) (return > 5)) > > (else 3))) > > ;;; <stdin>:2:42: warning: possibly unbound variable `return' > > scheme@(guile-user)> (test 2) > > ice-9/boot-9.scm:1685:16: In procedure raise-exception: > > Unbound variable: return > > > > > > any idea? > > Hi Damien, > > This is because of the "hygiene" rule of Scheme, where the notion of > "lexical > scope" is taken very seriously: for an identifier to be bound, it must be > visible in the lexical (textual) surroundings where it has been bound. > > So for instance, in the following example code: > > (def (test x) > (cond > ((= x 3) (return 7)) > ((= x 2) (return 5)))) > > We can't see a binding for "return" anywhere in the text, therefore it > cannot > be bound. > > This is good "default" behavior because it makes code more flexible and > easier > to understand. > > An easy way of overcoming this issue is to let the user explicitly name the > return identifier however they like: > > (define-syntax def > (syntax-rules () > ((_ (name ret arg ...) body body* ...) > (define (name arg ...) > (call/cc (lambda (ret) body body* ...)))))) > > Now you could define: > > (def (test return x) > (cond > ((= x 3) (return 7)) > ((= x 2) (return 5)))) > > Or for instance: > > (def (test blubba x) > (cond > ((= x 3) (blubba 7)) > ((= x 2) (blubba 5)))) > > However, sometimes you're sure that you want to make an implicit binding > for > an identifier, and for those cases you need to write an "unhygienic" macro > which can be achieved with the more complex macro system "syntax-case". > > Here's how your desired macro could be defined. I will use identifiers > like > "<foo>" just for easier readability; they don't have any special meaning: > > (define-syntax def > (lambda (stx) > (syntax-case stx () > ((_ (<name> <arg> ...) <body> <body>* ...) > (let ((ret-id (datum->syntax stx 'return))) > #`(define (<name> <arg> ...) > (call/cc (lambda (#,ret-id) <body> <body>* ...)))))))) > > There's a few things here to take note of: > > - Unlike with syntax-rules, the syntax-case is contained in a lambda which > takes a single argument: a "syntax object" which is passed to syntax-case > > - Unlike with syntax-rules, the "body" of the macro (where it begins with a > 'let') is not immediately part of the generated code; that 'let' is > actually > executed during compile-time. The body of the macro must result in an > object of the type "syntax object" that represents the generated code. > > - You see that I define a variable called "ret-id" which I bind to the > result > of the expression: > > (datum->syntax stx 'return) > > which means "create a syntax object in the same lexical environment as > stx, > and is represented by the symbol 'return'." > > - The actual code generation begins within the #`(...) which is a shorthand > for (quasisyntax (...)) just like '(...) is short for (quote (...)). The > result of a quasisyntax expression is a syntax object. Basically, it's > the > most convenient way of creating a syntax object, but like syntax-rules > it's > also hygienic by default and you need to insert "unhygienic" syntax > objects > into it explicitly. > > - Within the quasisyntax, I use #,ret-id which is short for (unsyntax > ret-id) > to inject the unhygienic syntax object that holds the symbol 'return' > into > the generated code. > > For someone used to macros in the Common Lisp or Elisp style, this may seem > over-complicated. It's the cost of the "hygienic by default" behavior. > > By the way I assume that you're just toying around with the language to > learn. > If you were thinking of using a 'def' macro like this in real code, I would > discourage it because there's already a built-in mechanism that allows the > programmer something very similar, called 'let/ec': > > (import (ice-9 control)) > > (define (test x) > (let/ec return > (cond > ((= x 3) (return 7)) > ((= x 2) (return 5))))) > > As you see it allows you to define a "return" keyword anywhere, and it > doesn't need to be part of a function definition, it can appear anywhere. > > -- > Taylan >