IRC channel logs

2025-08-19.log

back to list of logs

<mwette>Another option is to make a pattern file like vecops.scm.in and use sed or m4 to expand fl:* to * or fl* per impl.
<mwette>to generate vecops.scm
<ttz>why not for use with a make, but this is not repl friendly
<mwette>pattern file assumed to be processed by make or equiv
<ttz>Coming back to a point raised here couple days ago, why are libraries not expanded as declarative modules?
<ttz>It seems this prevents basic cross-library optimizations from being performed...
<ttz>Somehow it seems to prevent even basic syntax transformations: https://paste.debian.net/1392348/
<ttz>okay my bad for the last one there was a mistake in the export
<ttz>But trading the syntax definition for a regular definition prevents optimization.
<identity>i do not see anything in ice-9/r6rs-libraries.scm that would transform ‘library’ forms to #:declarative? #false modules…
<ttz>me neither, but you were the one bringing it up ahah
<ttz>but I checked ,expand (library (dummy) (export fl:*) (import (guile)) (define fl:* *)) and that's the case.
<ttz>So I don't know where this expansion comes from.
<ttz>greping through Guile's code-base didn't help much
<ttz>It is clearly stated in the R6RS spec that: "All explicitly exported variables are immutable in both the exporting and importing libraries." So I think making libraries declarative in Guile would make it even more compliant.
<identity>trying to ‘set!’ variables exported from ‘library’s should signal an error, arguably
<ttz>that's what the spec says indeed
<ttz>I found the line where #:declarative #t should be placed, I will try to compile Guile with that set, see if nothing breaks
<ttz>The only reason I can see why this hadn't been set before (apart from being forgotten upon adding the #:declarative option for modules) is to prevent inlining to explode compilation time.
<ttz>Guile is really slow at optimizing code compared to Chez for example. I don't really know why that is, but last time I wrote a macro to unroll a loop and setting the unrolling level to >=128 led to crazy compilation times.
<identity>Guile is just plain slower than Chez, and the compiler being written in Guile does not help
<ttz>It is slower, but I am still surprised how it can feel slow when compiling.
<lloda>my newra library takes a very long time to compile. Minutes, depending on how many types and ranks you inline. Wanted to try compiling on demand but i haven't figured out how to do that
<dsmith>ttz, Guile had modules long before there was an r6rs, and also long before Guile had a compiler.
<dsmith>It was a normal thing to be able to set! something from a moduele.
<ttz>Maybe, but I do not see how it explains the fact that libraries are not declarative modules.
<ttz>Modules may export mutable bindings, but R6RS don't.
<ttz>Btw, I have a failing test when trying to compile Guile on my machine using `guix build -f guix.scm`.
<ttz>I just sent a report to the debug-guile mailing list.
<ttz>I checked out the v3.0.10
<ttz>Is an executable produced in that case? Otherwise I guess I am unable to see what modifying the module declaration does on my machine...
<mwette>In my experience the Guile optimizier is slow w/ deep let's (e.g., from using sxml-match with large number of cases) and w/ large number of procedures.
<ttz>mmh that would match my experience with nested let to modify the loop variable at each unrolling level...
<mwette>I have an autogenerated .scm file that is 90k lines, 6000 defines. w/ guild compile -O0 or -O1 it compiles in 6 sec; with -O2 I give up after 6 min.
<ttz>I was unable to inline the updated variable directly in the unrolled expression so I wrapped them in let's.
<ttz>wow why did you need to generate so many lines?
<mwette>It's my ffi-helper: works like swig. That is the converted gtk2.h.
<ttz>really cool, can you automatically generate bindings for any C library?
<ttz>I had in mind hand-writing bindings for some formally proven cryptographic library but the very idea of the task was putting me off.
<mwette>It's not bad. https://www.nongnu.org/nyacc/nyacc-fh-ug.html
<dsmith>ttz, I remember reading somewhere that an optimization in the Chez compiler was only added if it made the compiler faster.
<ttz>I may try it in he future, thanks mwette
<mwette>IIRC, Guile optimization level 0 is the "baseline compiler" intended to compile fast.
<mwette>yw
<ttz>Can you get efficient FFI if you are reduced to using -O0?
<mwette>It seems to be OK. I use -O1 now. I believe -O1 will create JIT code whereas -O0 does not. (I could be wrong.)
<ttz>Isn't JIT a runtime concern (enabled by the VM) vs -O a compile-time concern (the quality of the produced byte-code)?
<mwette>The compiled code has to be instrumented for the runtime JIT compiler, I believe.
<ttz>True, even though I do no know if this belongs to one of the optimization passes.
<ttz>Would be good to have the table of optimization performed at each level somewhere
<mwette>system/base/optimize.scm
<ttz>I see no mention of instrumentation so I guess this is performed whatever optimization level.
<ttz>Great to keep this table in mind though. I note that there is almost no -O3 opt.
<ttz>This may explain the lack of difference between O2 and O3, ArneBab
<old>The only optimization in O3 is seal-private-bindings. AFAIK, using it can break existing program thus why it's put in O3 since O2 is the default
<old>but it's a good optimization. I use it and I can see some difference in performance
<ttz>What does it do?
<mwette>baseline compiler article: https://wingolog.org/archives/2020/06/03/a-baseline-compiler-for-guile
<old>ttz: At optimization level 3 and above, Guile will assume that any top-level binding in a declarative compilation unit that isn't exported from a module can be completely inlined into its uses.
<old>Note that with this new `seal-private-bindings' pass, private declarative bindings are no longer available for access from the first-class module reflection API. The optimizations afforded by this pass can be
<old>useful when you need a speed boost
<old>wonder if that works when the binding is used by a syntax-transformer that is exported
<mgd>Hello. I've just started to learn guile. Is there a way to see the source code behind some of the in built functions like `define` or `when`? I'm using geiser with emacs and I can see there is a function to view documetation but jumping to source (M-.) doesn't yield anything
<old>mgd: best way to find source code, is to grep the Guile source code.
<old>Usually, grepping for `define X' should yield good places to look for
<mgd>ok. is this stil the repo link? https://cgit.git.savannah.gnu.org/cgit/guile.git/tree/
<old>I use https://git.savannah.gnu.org/git/guile.git
<old>sometime it helps if you know something is a syntax or other kind of define
<old>grepping for `define-syntax when' (lazy search) I found:
<identity>mgd: i just open the local guile scheme source files and grep, you should have it in /share/guile/3.0/ or somewhere like that; i doubt you will find anything on ‘define’, as it is likely a form internal to the implementation
<old>Under module/ice-9/boot-9.scm:419
<old> 419 (define-syntax-rule (when test stmt stmt* ...) 420 (if test (begin stmt stmt* ...)))
<mgd>Thank you. I've cloned the repo. I've had to work on a mac and I'm not sure where the installation is other than the binary for guile.
<mgd>I guess i've been spoilt with the likes of Intellij that let you see the source for methods
<old>I would not mind having this feature like Emacs has for its code
<mgd>It's helped me in the past to understand Java
<identity>yeah, it is kind of annoying that currently xref does not mork with built-in forms
<old>wonder if we could make ctags works with scheme hmf
<mgd>I've been trying to read SICP and saw that define was a 'special form'. I thought seeing the source would help me understand more about that
<rlb>mgd: another likely place for definitions is in C in libguile, typically via SCM_DEFINE.
<mgd>Yes, I found the functions for boolean operatiors in that directory but not define yet. I must be there somewhere
<identity>mgd: not sure if this helps, but here i go: special forms get their arguments ‘raw’ (think like plain lists with no evaluation), but also they have access to some things that the language itself does not, for example the ‘if’ form only evaluates one of the branches, by having access to a way to choose between them depending on a boolean that would be impossible to implement in plain scheme unless you are implementing another
<identity>scheme inside of your scheme, and at that point the need for branching on a boolean would likely show up before you get the chance to implement it…
<rlb>mgd: perhaps git grep -F '"define"' if you're saying you're still looking for the definition of define.
<rlb>i.e. expand.c -- though I haven't looked to see if that's probably the "right" one.
<identity>macros are similar to special forms, but they do not have access to ‘super-linguistic’ (not sure if i used that right) features like being able to implement branching on a boolean value
<identity>though, i suppose, you could implement branching on a literal boolean as a ‘syntax-rules’ macro, reminiscent of smalltalk: ((if #t then else) (then)) ((if #f then else) (else)) where ‘then’ and ‘else’ are supposed to be thunks (zero-argument procedures)
<mgd>I don't think I even get what a macro is properly yet! Thank you for the input though. I think I understand that they work differently to normal lisp forms in that they start with a function and rest are arguments
<mwette>To evaluate the function call (foo c t f) the expressions c t f first need to be evaluated (well, foo as well). `if' is not a function call, but syntax, so when the interpreter sees `(if' it will generate code to first evaluate c and then either t or f. If you wanted to create a functional form of `if' say if-fun it would have to be called like (if-fun c (lambda () t) (lambda () f)).
<mwette>The thing to understand is that when you write (foo ...) foo could be a function or could be syntax. They are different. At the guile repl, type `max' and then `if' (w/o surrounding parens).
<ieure>They left.
<mwette>Ah. Thanks.
<ieure>You can, of course, define a macro that works like `if'.
<mwette>Sure. But you see why a lot of procedures in scheme take thunks for arguments. In many cases w/o thunks you need syntax.
<identity>that is what they do in smalltalk, actually: “True ifTrue: [consequent] ifFalse: [alternate]”, where [] denote code blocks (like anonymous functions), and ifBool: is the message send syntax; when a True object receives an ifTrue message, it executes the code block, and when it receives an ifFalse message it ignores the code block, vice versa for the False object