IRC channel logs

2023-10-07.log

back to list of logs

<mwnaylor>Unfortunately, the emaccs builtin info has a problem with the idices for Guile. Plus side, it gave opportunity to build an extersion that calls up an external terminal (konsole) running "info guile".
<RhodiumToad>how so?
<haugh>Standalone info ftw! I run it in a vim terminal
<daviid>RhodiumToad: fwiw, i released 0.8.0-rc-1
<daviid>sneek: later tell tohoyn now comes the time to get g-golf in debian 'proper', let me know if there is something i can do to help ... thanks
<sneek>Will do.
<RhodiumToad>daviid: thanks for the heads-up - I should get email from portscout within a day or so of new releases anyway, but it's appreciated
<rlb>mirai: if you still want a portable /usr/bin/env application, perhaps something like this:
<rlb> #!/bin/sh
<rlb> exec /usr/bin/env guile -s "$0" "$@"
<rlb> !#
<rlb>
<rlb>mwnaylor: guile's define-macro is much more like clj's defmacro, i.e. unhygenic (though clj's are a bit safer most of the time because of the reader's symbol namespacing trick), and syntax-rules and syntax case are *much* fancier, though yes, particularly the latter, perhaps also a bit more to digest.
<RhodiumToad>you can do a lot with syntax-rules
<rlb>yep.
<rlb>And if you just need a little bit of "not hygenic" and are coming from clj, suppose you could just start with define-macro and work your way up...
<rlb>(for those bits)
<rlb>Though clojure's defmacro really is a bit safer in the common cases because the symbols are rewritten to include their namespace (clj has namespaced keywords/symbols).
<rlb>("keyowrd/symbol refrerences" I should probably have said)
<RhodiumToad>ACTION mutters about the lack of syntax-parameter-value
<rlb>ACTION doesn't know the context there yet.
<RhodiumToad>syntax parameters are a useful and usually better alternative to many uses of with-syntax to unhygenically introduce a keyword
<RhodiumToad>but without the ability to rebind the old value of a parameter, it breaks if you have a macro foo that uses a syntax parameter, and you try and use it in a macro bar that might be applied to expressions that also use foo
<rlb>Oh, yeah (re-read the section), I haven't really tried to understand/use them much yet -- just handled things the messier way in the more complex things I've needed to do lately.
<rlb>And I found the (racket?) doc for syntax-parameter-value -- it returns the current transformer or whatever that's associated with the parameter? (Still only vaguely understand it...)
<rlb>haugh: regarding clj docs, at least for me, I generally use the universally built in docstrings via (doc something) or emacs/cider, which pretty much always works, and is comprehensive for the clj "core", then the online docs like https://clojure.github.io/clojure/clojure.core-api.html and the overview via https://clojure.org/about/rationale. There are also a decent number of fairly approachable books.
<RhodiumToad>yeah, the idea is that you do (with-syntax ([old (syntax-parameter-value #'param)]) ...stuff... (syntax-parameterize ([param old]) body ...) to get "body ..." (presumably a parameter) expanded with param bound to its old value rather than some value bound for the current macro's purposes
<rlb>haugh: but clj doesn't afaik have anything like guile's info pages and/or reader, which I find quite useful in its own right, with different strengths.
<RhodiumToad> http://scheme2011.ucombinator.org/slides/Barzilay2011.pdf
<rlb>Oh, thanks.
<rlb>When trying to do some of the more complex lokke macros (by far the most complicated scheme macro stuff I've ever attempted), it became clear just exactly where I did and didn't fully understand a thing :) In particular, I was very surprised that the "literals" didn't work the way I expected, i.e. aren't just raw symbol matches (which is what was required). I basically can't use them, and have to rely on syntax->datum based guard
<rlb>clauses...
<RhodiumToad>example?
<RhodiumToad>the usual hazard with literals is that they only work as literals if not bound somehow
<rlb>I was afraid you were going to ask that.
<rlb>Oh, right, and that was it, they were sometimes "captured" and then it was very hard to figure out what was going on :)
<rlb>...and I never want(ed) that possibility, i.e. in a clj loop/recur the recur should always either be the form's recursive invocation, or a "shadowing" local binding (not sure clj defines the latter, but I just matched clj/jvm there).
<RhodiumToad>that looks like it should be a syntax parameter and not a literal
<RhodiumToad>though I don't know clj and may be misunderstanding
<rlb>Might be right -- and certainly happy to change it if that turns out to be the case.
<RhodiumToad>do you have a simple example?
<rlb>That's one "on the other hand" wrt clj. The language is only partially specified. i.e. in some cases I just had to go see what clj/jvm did and match that. (Other likely candidate would be cljs, but that's not nearly as similar an envt, and not nearly I'd guess as heavily used, though who knows web-wise...)
<rlb>guile/scheme's much better on that front in general.
<RhodiumToad>ok, from random googling, it looks like loop/recur is like a named-let that binds a fixed name?
<rlb> https://clojure.org/reference/special_forms#loop
<rlb>loop recur is clj's practical concession to the fact that the jvm can't do real tail recursion atm (if ever).
<rlb>It's like a very limited let-loop.
<rlb>(oh, right, named-let :) )
<RhodiumToad>right. this looks _absolutely_ like recur should be a syntax parameter
<rlb>Another complexity in implementing a clj dialect and strength on the guile/scheme side, is that they still haven't had to yet really wrestle with the "environment" question, i.e. compile time vs run time vs...
<rlb>ACTION was also just trying to get "everything" working where there was a lot of everything, and so some of it's still just "expedient hack" that's hopefully not too wrong :)
<rlb>ACTION goes to look at what's there now...
<RhodiumToad>anyway, afk
<rlb>OK, fwiw, if you're interested: https://codeberg.org/lokke/lokke/src/branch/main/mod/lokke/base/syntax.scm#L310-L332 I'd be completely unsurprised if that's not a really great way to have done it :)
<rlb>right
<rlb>A couple of notes there -- the let** is clj's full destructuring let, and the vec-tag stuff is related to the handling of compile time (persistent) vector literals like [1 2 3].
<rlb>(and clojure's "metdata" that you can "attach" to various things -- lokke attempts to hack in some of that, but some bits just won't go without breaking the close correlation with the scheme side)
<rlb>mwnaylor: you're also welcome to badger me if you like wrt figuring out how to map/find things wrt clj vs scm/guile.
<mwnaylor>rlb: can define-macro be made more hygenic w/ something like gensym? I'm not strong w/ macros, tbh. This is the best I've been able to do w/ elisp. https://pastebin.com/0MRL2Dv9
<rlb>mwnaylor: right gensym is what you want in place of clj's "x#". Clojure's doing something similar for you, but neither are hygenic -- hygenic is "much fancier", or rather is "actually doing the right thing" :)
<mwnaylor>I'm a little fuzzy on the definition of hygenic. My general impression is that local symbol/identifier don't shadow others and that s-expressions that enter via parameters only get evaluated once.
<rlb>mwnaylor: and if you don't already "get" hygene, one simple example is that gensym and x# just create a normal symbol that user code (say in the ~@body) could be using either accidentally or maliciously, and now you may have a problem.
<rlb>With hygenic macros, that's just impossible, because the "symbols" aren't just symbols, they represent distinct bindings in the scope they came from, that are guaranteed to be distinct.
<rlb>Whereas any given x# is just 'foo-123 and anyone can use that, and there's only one.
<mwnaylor>Scope binding IS something that I can grasp.
<rlb>hygenic macros are "hard" the other direction, when you *want* to collide/override other things.
<rlb>You have to do some work, but that's certainly the better default behavior :)
<rlb> (define-syntax-rule (nor args ...) (not (or args ...)))
<rlb>Though define-syntax-rule is I think possibly guile-specific.
<rlb>(just a simplification of some common define-syntax/syntax-rules cases)
<rlb>i.e. just syntactic sugar for
<rlb>(define-syntax nor
<rlb> (syntax-rules ()
<rlb> ((_ args ...) (not (or args ...)))))
<rlb>mwnaylor: and if you used core.match a lot, might be interested in guile's (ice-9 match).
<mwnaylor>Not familiar w/ core.match.
<rlb>ACTION suggests it when you're in clj :)
<rlb> https://github.com/clojure/core.match
<rlb>(fancy)
<mwnaylor>Just did a quick search. Seems to be similar to the match in Scala.
<rlb>guile's match is in the info pages, though might take a bit to "get it", as mentioned here recently, those docs could perhaps be improved.
<rlb>It'd be really nice if we eventually had something like ring well maintained and readily available (if we don't already), and I'd like to see some kind of thread pool abstraction (guile has one atm, but it's not in any way re-usable or abstracted). That'd be handy for me wrt implementing some lokke/clj bits (like atoms, agents, etc.), and should be useful more broadly too.
<rlb>iirc the current hard-coded pool is just for futures.
<rlb>wingo: rebased utf8 onto current main and pushed -- seems fine.
<RhodiumToad>mwnaylor: expressions passed to hygenic macros aren't necessarily evaluated once (or at all) - consider a loop macro for example
<RhodiumToad>e.g. (do ...) is a macro
<RhodiumToad>rlb: this is the basic idea of loop/recur with syntax parameters: https://dpaste.org/5UMRA
<RhodiumToad>note that (... ...) is a way of escaping ... in nested syntax definitions
<rlb>right
<RhodiumToad>I didn't try and figure out the clj binding syntax
<rlb>If you mean the full binding syntax, then we just have to hand that over to let** -- that's one of the most complex bits, other than the lower-level compiler stuff, i.e. https://clojure.org/guides/destructuring
<rlb>So was your earlier grumbling about syntax-parameter-value relevant there? I wasn't sure yet whether that was something it would be "nice to have", or serious missing functionality...
<rlb>Oh, and thanks for the help.
<RhodiumToad>the need for syntax-parameter-value only shows up if you want to use loop/recur as part of a hygienic macro itself
<rlb>clj's destructuring is like a mostly fancier "always on" (ice-9 match) style thing.
<rlb>Ahhh, ok, that helps.
<rlb>(And I suspect I don't in lokke's internals.)
<RhodiumToad>i.e. suppose you wanted to write a macro foo that used loop around passed-in expressions which might contain a (recur) form
<rlb>I'd just use scheme.
<rlb>In general, but in this case even more so, since loop/recur is just a workaround for the fact that you can't have nice things (real TCO) on the jvm.
<rlb>("always on" -> works for let bindings, function parameters, etc.)
<apteryx>how can I write to the beginning of a file in guile? perhaps some open mode?
<rlb>apteryx: perhaps "w+" or "wb+" for the mode, depending on what you need
<RhodiumToad>with or without truncating?
<rlb>If you mean, how do I overwrite the contents in-place.
<rlb>(And for more info, see the "open-file" docs in the info pages.)
<apteryx>nope, I mean cat <(echo "my new content on first line") the-file.txt > the-file.txt
<apteryx>ACTION checks what w+ does
<civodul>“w+” and “r+” are for read+write
<rlb>apteryx: yeah, then you likely just need "w" or "wb", which will clobber any existing content.
<rlb>or the simpler...
<RhodiumToad>apteryx: that doesn't work even in shell
<apteryx>probably forgot a dollar
<RhodiumToad>apteryx: since you're clobbering the-file.txt before reading it
<rlb>oh, wait, I didn't read.
<apteryx><$(echo ...) ?
<rlb>yeah, you can't do that, possibly :)
<RhodiumToad>(echo "new content"; cat oldfile) >newfile && mv -- newfile oldfile
<RhodiumToad>and in guile you have to do basically the same thing - writing a new file and renaming it over the old one
<apteryx>ah, indeed it fails with a input file is same as output file
<rlb>Anyway depending on where you end up, open-output-file, or call-with-output-file might be interesting.
<apteryx>so I have no choice but to read it all then write destructively on top of it (after doing whatever with its content)
<RhodiumToad>there's no way to insert into a file
<spk121>ACTION is setting up my build environment for Autumn Lisp Game Jam 2023
<RhodiumToad>(other than by copying the whole thing)
<mirai>RhodiumToad: there's `sponge' from moreutils that can avoid this cloberring
<mirai>clobbering*
<rlb>apteryx: you could also rename the existing file to a temp name, then stream from it, and delete it at the end.
<rlb>but yeah, no "insert" in posix.
<rlb>nor "splice" at least not one that does that (linux splice is something different)
<apteryx>maybe something like this: https://paste.debian.net/129436
<apteryx>it's naive but I'm not worried about a multi gigabyte file
<rlb>ENOENT?
<rlb>i.e. nothing at that url atm for me
<apteryx>oh, https://paste.debian.net/1294362/
<apteryx>I had stripped the last char, apologies
<RhodiumToad>that call-with-output-file looks very wrong
<old>I have a questiong regarding syntax transformer. Is there a way to introduce a `define' at the top level when expanding in a procedure?
<old>I want to expand some syntax into multiple define of procedures that does not capture anything inside a procedure
<old>and I would like to avoid that these definitions be done everytime the procedure is called
<old>I think that what I want is something similar like the `static' qualifier of a variable in C
<civodul>you’re concerned about the run-time cost of internal defines within a procedure?
<old>civodul: yes!
<civodul>if the code is compiled, you can ignore that
<old>say I define a procedure A within a procedure B. But A capture nothing in B. B simply passed inputs to A to get a result.
<old>oh really?
<civodul>so yes, in that case the compiler will DTRT
<old>I thought that A would be evaluated each time B is called
<old>what's DTRT?
<civodul>well A is essentially lifted out of B
<civodul>no closure is allocated in that case
<spk121>"DTRT" Do The Right Thing
<old>aaah
<civodul>oh right, sorry
<old>but see this code for example:
<old> https://paste.sr.ht/~old/b18838827481a93c46434afe050e343216323455
<old>Now I know that I'm suppose to do instead (define foo (let ((static-counter (make-counter))) (lambda () (static-counter))))
<old>is this because static-counter is not a procedure and so can not be lifted out?
<civodul>here ‘make-counter’ necessarily allocates a closure, it cannot be optimized out
<old>because it captured X ?
<apteryx>RhodiumToad: ah yes, it wants a proc
<civodul>old: yes, it returns a lambda that closes over a variable that it mutates
<civodul>so no inlining or partial evaluation that can help here
<apteryx>RhodiumToad: https://paste.debian.net/1294366/ looks better?
<rlb>apteryx: as RhodiumToad suggests, you'll need to do writes from within a call-with-output-file thunk.
<old>civodul: okay. And so there is no way to have this kind of static variable that needs an allocation?
<rlb>apteryx: that looks more likely
<old>civodul: Outside of defining it at top level
<civodul>old: correct
<civodul>but i guess a look at the bigger picture would help understand whether this matters at all
<civodul>allocating a closure remains quite cheap, so it all depends on what this code is doing
<old>civodul: if you want to take a look at this: http://oldiob.dev/guile---glob-patterns.html
<old>it's a simple blog post I made last year I think for glob pattern matching in Guile
<old>The section "Matching patterns" is what I want to optimize
<old>I do not want to recompile the patterns everytime a function that use them is called
<old>well actually I did some memoization on the patterns, but still that require a hashmap lookup
<RhodiumToad>you want the macro to expand into something that has the precompiled pattern?
<old>which involve locking mutexes ..
<rlb>wingo, civodul: wrt the parallel testing patches - would the next step be to repost after I fix up the commit messages, or were y'all wanting me to go ahead after I do that (if I don't find anything else I'd like to adjust), or...? Assuming y'all already had something in mind.
<wingo>rlb: commit :)
<rlb>"go ahead and merge it"
<rlb>Ahh, ok. Thanks.
<rlb>wingo: and any opinion yet about https://lists.gnu.org/archive/html/guile-devel/2023-05/msg00027.html No worries if it's still on the back burner.
<wingo>rlb: on that one, i would rather extend var lookup to recursively search uses
<haugh>given (syntax-case x () ((foo bar) ...)) would #'foo and #'bar be equivalent in terms of datum->syntax, since they both have the same "dynamic environment"?
<wingo>i agree with the result but i think the mechanism needs fixing, to handle other cases
<rlb>OK, no worries. I wasn't at all sure about what I'd done there in the first place :)
<haugh>uhh, by the above I mean the template-id argument of datum->syntax
<haugh>oh sorry this should go in #scheme