IRC channel logs

2025-07-08.log

back to list of logs

<omentic>hi all -- embarassingly, i'm kind of getting really owned by the module system right now. how do i use a module from another file in the same directory as my new module?
<rlb>Hmm, should just need (use-modules (some module)) as long as the parent directory of some is in the load path.
<omentic>can you elaborate on that "as long as"?
<omentic>i'm running "guile myfile.scm" to run the program. does that not add the current directory to the load path?
<rlb>It'll need to be in the %load-path, often set via GUILE_LOAD_PATH, if it's not in one of the "standard" directories.
<rlb>No -- and you probably wouldn't want it to by default since that's the "." in path style of security risk.
<rlb>"." in PATH (I mean, shell-wise)
<rlb>So
<rlb> GUILE_LOAD_PATH="$(pwd)" guile ...
<rlb>might work for you for now
<rlb>There's also a related -L if you'd prefer an argument.
<omentic>hm.
<rlb>guile -L "$(pwd)" I think
<omentic>is -L recommended?
<rlb>I'm not sure -- I've often used GUILE_LOAD_PATH, but that's mostly from scripts, and it's possible they might take affect at slightly different times, but I suspect either's likely fine in your case.
<rlb>(and easy to change later if you want to)
<rlb>You can also mess with %load-path from your scheme code.
<omentic>ok, interesting. do ppl use some standard build tool when they have larger projects?
<rlb>I don't know, in general -- I think one common option is just to rely on guix, and of course for people already involved with guix, but I don't have a lot of experience there myself yet.
<omentic>also -- GUILE_LOAD_PATH does work, but it only seems to work when i have (define-module (filename)) in the file i want to import. can i have anything other than (filename) there?
<omentic>hmm, i'll poke around and look for how to use that, thx
<rlb>You'll want it to match the location of the module.
<rlb>i.e. (define-module (foo bar) ...) for a module in foo/bar.scm in the load path.
<omentic>ah, i see. ok, maybe i should do -L .. then to do a bit of namespacing
<rlb>Also these days personally recommend always #:select(ing) your imports instead of importing everything via "no #:select".
<omentic>oh? interesting i'll check that out
<rlb>It's a bit more work up front, and more "noise", but I find it very nice to make it totally obvious where all the bindings came from, and also to not be susceptible to collisions if the module adds new exports later.
<rlb>e.g. https://codeberg.org/lokke/lokke/src/branch/main/mod/lokke/scm/atom.scm
<omentic>ah cool! i see
<ArneBab>wingo: nice! Thank you for the update!
<omentic>i'm curious, any reason guile has define-syntax-parameter and syntax-parametrize but no syntax-parameter-value?
<dsmith>wingo on wasm: https://queue.acm.org/detail.cfm?id=3746171
<ttz>Is syntax-case suitable to produce a specialized inner-product procedure on one of its two input vectors, with a fully unrolled loop?
<ttz>I have tried a few things but macros are still hard for me...
<dodoyada>probably, yes, but a concrete example would go a long way
<ttz>I would like a macro (specialize-inner-product v) to return a procedure (lambda (v*) (+ (* 4 (vector-ref v* 0)) (* 1 (vector-ref v* 1)) ...)) given v is (vector 4 1 ...).
<ttz>with an extra check on v*'s length (unless (= 34 (vector-length v*)) (error "unequal argument lengths")) given (vector-length v) is 34.
<ttz>The value of v would only be available at run-time.
<dodoyada>I'm not familiar with inner-product but this looks very map/reduce-y to me. Does it need to be a macro?
<ieure>Yeah, this is also what I'm wondering, I'd probably write a function that returns a lambda that uses reduce or maybe a transducer to do the work.
<ttz>I need it to be specialized on one of the two arguments, with loop fully unrolled
<ieure>Doesn't feel like a situation where a macro adds anything.
<mwette>ttz: for it to be a macro your expanded vector would have to be a literal
<ttz>okay, thanks mwette
<ttz>Is there a way to unroll a loop which depth is only available at run-time ?
<mwette>should be but let me see ...
<ttz>for information, I have already implemented an inner-product procedure that way: (define (inner-product v w) (vector-fold (λ (a x y) (+ a (* x y))) 0 v w))
<identity>is there really a need for the unrolling though?
<ttz>that's the hot-spot of my program, and I really would like to make some performance improvement
<ttz>unrolling would remove length check at each iteration
<ttz>and specializing the vector reference on the known argument
<ttz>otherwise I am rather pleased by Guile's performance, this inner-product procedure runs in 50us for vectors of dimensions 384 on my PC :)
<mwette>ttz: I came up with this but looks like optimizer did the right thing but not sure: https://paste.debian.net/1384922/
<mwette>oops maybe not; it does not work ; need to fix
<ttz>mmh you think simply expressing it in a currying fashion allows the optimizer to perform the work?
<mwette>that is my hope
<mwette>here is working version: https://paste.debian.net/1384923/
<mwette>this one doesn't look like it's generating fast code
<mwette>you could generate a sexp for the code and feed that to compile, I guess
<ttz>no it didn't, it's twice as slow as my original procedure :/
<mwette>I assume you don't know the one vector when you call the specializer. That is, you don't have a literal vector. Is that right?
<ttz>yes, that's why I wanted to use syntax-case: to generate sexps
<ttz>No I don't
<ttz>I have bunch of IP to compute for different vectors, and many of them with the same first argument
<ttz>but that argument is determined at run-time
<ttz>So to generate sexps, should I simply do it "by hand"?
<mwette>I'm working on something.
<dthompson>I have done hand-written matrix multiplication for small 4x4 and 3x3 transformation matrices, but for larger things I'd use a syntax-case macro to generate the code
<mwette>But he does not know the coef's at compile time.
<dthompson>like the size?
<mwette>I was approching to generate '(+ (* 1 y[0]) (* 2 y[1]) ...)
<ttz>I have done it "by hand" : https://paste.debian.net/1384927
<mwette>this: https://paste.debian.net/1384929/
<ttz>So now I can generate a procedure that takes the second vector and computes the IP withtout loop
<ttz>cool, similar code :)
<ttz>so can I call compile ?
<ttz>which module do I need to import ?
<mwette>`compile' is included in booted guile; no use-module needed
<mwette>`compile' takes args for things like optimization level etc.
<mwette>I wonder if multiple binary + would be faster than + w/ > 2 args
<mwette>i.e., (+ (* 1 y[0]) (+ (* 2 y[1]) (+ 3 y[2])))
<ttz>Good idea, it may seem like it from a quick timing
<ttz>but the dominant factor here is *
<ttz>I don't seem to have compile available inside my module...
<ttz><stdin>:70:5: warning: possibly unbound variable `compile'
<mwette>hmm. it's in mine; maybe (use-module (system base compile))
<mwette>Also, if you're using floats maybe (unless (inexact? (vector-ref y 0)) (error "optimized for floats")) as the first line will help; <= to give compiler a hint that this is float only
<ttz>thanks, I will try adding this hint
<ttz>after some tries, it seems that the manually unrolled procedure is faster for small dimensions (e.g. 13) but slower for big ones (e.g. 234)
<mwette>Is there one + or 233 of them?
<ttz>233 of them
<mwette>OK. Then I can't guess what the growth may be from.
<ttz>The number of instructions to perform in case of a high dimension is huge (~6000). Maybe the overhead of loading them to memory start to matter at that scale?
<ttz>I think I remember Knuth talking about something like that, but I cannot find it back...
<daviid>for larger matrix multilication, providing you agree to only work with float32, you might consider using guile-cv, or aiscm
<dsmith>Maybe cache locality?
<ttz>yes something like that would be my guess
<ttz>thanks daviid I will have a look at it
<daviid>ttz: if guile-cv, make sure you read and configure guile for guile-cv, as explained in the manual - https://www.gnu.org/software/guile-cv/manual/guile-cv.html#Configuring-Guile-for-Guile_002dCV - otherwise, it is unusable, due to a lack of proper guile (core) way to truncate exceptions (output)