IRC channel logs


back to list of logs

<dadinn>so if i have a pattern (foo bar bar* ...) , and i call the macro with (foo 1 2 3 4), then what does bar and bar* bind to?
<erkin>bar binds to 1, bar* binds to 2 3 4
<erkin>bar* is not a list, mind you. It's literally multiple syntactic elements at once.
<erkin>It might make things easier to consider the template system a separate, Scheme-based DSL than Scheme itself.
<dadinn>i assumed it is such
<erkin>Had you defined it as (foo bar . bar*), bar* would be (2 3 4), merely a list.
<dadinn>ok,then i clearly don't understand :)
<erkin>... makes it very easy to write recursive macros where you have two templates: (foo bar) and (foo bar bar* ...). If the cdr of the form has only one element, it matches the first template. Otherwise, it falls back to the next one.
<erkin>In the (foo bar bar* ...) clause, you can recurse on the macro as (foo bar* ...) to call it again with the rest of the forms given.
<erkin>Until only one element remains, then it can match the first (foo bar) clause.
<erkin>You can also write mutually recursive macros similarly.
<dadinn>so when ... is used in the template it is like ,@ ?
<erkin>I wouldn't say so, because ,@foo expands *from* a list foo, whereas foo ... was never a list in the first place.
<erkin>It's literally everything the parser matches.
<erkin>You can also have nested ellipses for macros generating macros that use ellipses but that's a huge pain in the butt IMO:
***hugh_marera_ is now known as hugh_marera
<dadinn>so you would recommend I should stick with the cons form instead?
<erkin>If it does what you want, yes. It's much easier to deal with.
<erkin>I need to go to sleep now. I hope I managed to help you.
<erkin>I do agree that there needs to be more newbie-friendly tutorials for Scheme's macro systems (there are seven different ones in use today, across separate implementations, although everyone uses `syntax-rules' for nearly everything).
<erkin>I was writing a tutorial myself but got sidelined by work and such. :-P
<dadinn>one more question, how does syntax-rules save me from something like: (let ((with-output-to-file (lambda (path) (error "Called the wrong one" path)))) (with-my-output-to-file "test.txt" (display "foobar")))
<erkin>Not sure I get the question.
<dadinn>i've noticed on the tree-il it says (toplevel with-output-to-file) but I don't understand
<erkin>Oh I think I see.
<erkin>Yes, at expansion time, the `with-output-to-file' in `let' bindings is a separate symbol from the one in `with-my-output-to-file's definition.
<dadinn>how does it guarantee that the with-output-to-file is taken from the context the macro was defined, and not where it was expanded
<erkin>The standards leave the underlying implementation to the implementers but most of the time it's an automatically computed gensym system.
<erkin>Something like (let ((with-output-to-file~1 (lambda () 'junk))) (with-output-to-file~0 "text.txt" (lambda () (display "foobar"))))
<erkin>Where `with-output-to-file~0' is bound to the original top-level definition.
<erkin>Again, it's implementation dependent but that's the gist.
<dadinn>so the toplevel node I see in the Tree-IL is not a function object itself captured at the point of definition?
<erkin>You could say that, yes.
<dadinn>sorry, my question was in the negative, but actually I meant that that is what I would assume it was :)
<erkin>Oh sorry
<erkin>I'm not entirely sure how Guile does it in particular but it captures the environment at the time.
<erkin>Fun fact: You can write macros that break hygiene (in a way) by nesting macros and abusing the literal list with forced captures:
<erkin>It's practically impossible to do it by accident though.
<erkin>If you do want to break hygiene for sure (eg given a symbol `foo', you want to define `set!-foo' and `get-foo' in a macro), there's `syntax-case', a heavyweight superset of `syntax-rules' that comes with all sorts of utilities for operating on syntax objects. It's admittedly rather baroque and difficult for newbies to grasp (probably to discourage breaking hygiene at all).
<erkin>Ah, I need to sleep already.
<erkin>Good night!
<dadinn>erkin: Good night! thanks a lot!
***apteryx is now known as Guest29175
***apteryx_ is now known as apteryx
***sneek_ is now known as sneek
***janneke_ is now known as janneke
<rndd>hi everyone! i don't understand these code . Does length work as variable and can store numbers and is it 0 by default?
<nalkri>Length is a function that if it gets an empty list (the "null?" test) returns 0, if it gets a non-empty list it returns one plus the length of the same list minus its first element
<nalkri>That may or may not help :p
<rndd>nalkri: but where sum is stored -_-?
<nalkri>In the stack, if it's actually evaluated as a recursive function (I think it would be optimised to a loop really)
***rekado_ is now known as rekado
<rekado>rndd: it is not really “stored”
<rekado>try substituting the calls to “length”
<rekado>first try with the empty list
<rekado>(length '()) becomes (if (null? '()) 0 (+ 1 (length (cdr '()))))
<rekado>that becomes (if #t 0 (+ 1 (length (cdr '()))))
<rekado>and that becomes just 0
<rekado>let’s try a longer list '(a)
<rekado>(length '(a)) =>
<rekado>(if (null? '(a)) 0 (+ 1 (length (cdr '(a)))))
<rekado>(null? '(a)) is false, so the “if” expression becomes (+ 1 (length (cdr '(a))))
<rekado>(cdr '(a)) is '()
<rekado>so that’s (+ 1 (length '()))
<chrislck>rndd would find time watching the first few SICP videos very well spent
<rndd>ohhh, so it becomes (+1 (+1 (+1 (+1 ... 0) ?
<chrislck>(1+ (1+ ... (1+ 0))))) yes
<nalkri>Thank you, and sorry for my lack of explanation
***logicmoo is now known as dmiles
<daviid>str1ngs: ar you connected to (today)? I can't connct to either, nor today ...
<guix-vits>daviid: i'n not str1ngs, but those works for me.
<daviid>guix-vits: ok tx, i wonder why not 'here'
<daviid>guix-vits: hum, tx that worked ...
<daviid>I'll rport that to the gnome tam it's getting mor and more difficult ro connet to their servers ...