IRC channel logs
2025-07-16.log
back to list of logs
<trannus_aran>does anyone have recommendations on base64 encoding packages for guile? <trannus_aran>I see there's a (guix base64) module with functions that work on bytevectors, but I'm not sure what package that's in to list in a guix.scm inputs list? <rlb>trannus_aran: here's a preliminary srfi-207 for guile that may or may not eventually be adopted whole or in part. If it has the functions you need, then for now you could probably just "vendor" them -- they're pure scheme (it's much the reference implementation): https://codeberg.org/rlb/guile/src/branch/tmp/srfi-207 <rlb>Hmm, though the guix package is presumably better if you're already using guix bits and it does what you want. <rlb>(and maybe better regardless) <trannus_aran>that's the thing, this is already for a very guix-y production environment <meaty>hello #guile, what module is sxpath in? the documentation doesn't give a clear answer <rlb>meaty: not sure, but "git grep sxpath module/" suggests (sxml xpath). <meaty>rlb: that seems to be it, thank you <rlb>imagine the docs might need augmentation <rlb>if they don't say or have related examples <meaty>hmm... and I'm not sure if it's what I'm looking for after all. is there a function like "match" or "sxml-match", but it can return an s-expression matching a pattern *somewhere* within a larger expression? or am I missing something <meaty>I'm trying to write a script to merge RSS subscription lists (opml) <rlb>There's general-purpose (ice-9 match), but I don't know much about the sxml modules. <trannus_aran>hey rlb you know if there's a good way to read an image file into bytevectors (assuming rnrs bytevectors is already imported and you've got a file handle from with-open-input-port and such)? <rlb>image as in graphics, fs, or...? <rlb>For just "get the data", perhaps get-bytevector-all? <rlb> (use-modules (ice-9 binary-ports)) <rlb>(And for image related stuff, I know *of* guile-cv, but am not familiar with it.) <trannus_aran>ah nice! I was looking through the docs and thought that the binary ports was the way to go :) <trannus_aran>yeah, might use guile-cv, but that's probably overkill? All I need is to take a jpg, encode it to a base64 list/vector/bytevector/whatever and then pass it to a couple functions I already know work on BVs <rlb>Ahh, yeah, that'd be built-in if srfi-207 were already included I suspect. <trannus_aran>I try to run it but no dice, guile complains of a bad let form <cow_2001>argh i keep getting that weird flathaired streetfighters character in search engines! <cow_2001>someone please rename the project to "not street fighters' guile" <dsmith>trannus_aran, As fas as I know, normal let doesn't do multi-value bindings. <dsmith>scheme@(guile-user)> (let ((a b (values 1 2))) (list a b)) <dsmith>unknown file:1:0: let: bad let in form (let ((a b (values 1 2))) (list a b)) <dsmith>trannus_aran, Maybe they have redefined let somewhere? <dsmith>There is a let-values in srfi-11 <mange>srfi-71 lets you use let like let-values. <lloda>imo srfi-71 should be in the default env <ArneBab>lloda: I’d like let with values, but I don’t think uncons unlist and unvector should be in the default env. <lloda>fair, then just srfi-71's let should be default let <lloda>tbh i've never used the un- functions <ArneBab>lloda: I think that needs testing whether there’s a performance impact, but if there isn’t, I agree. <ArneBab>(both on compile times -- at least no big one -- and on runtimes) <dodoyada>I have an issue where I copied a `define-module` (A) to a new file to create a new module (B). I changed the module name and evaluated in the repl but I did not change `#:export`s. After that first load I changed exports and wrote a placeholder function that I then used in a module (C) that depended on both the original and copy module. Now though it says C has imported the same export from both A and B. How do I clear this up <dodoyada>I restarted my repl and found I was missing a use-module that I was trying to use so B wasn't actually compiling. I imagine it does reload B appropriately as long as it compiles though I need to figure out why I wasn't seeing that before repl restart <ieure>dodoyada, Not sure if Geiser supports this, but C-u C-c C-k in other Lispy Emacs modes usually nukes the namespace before loading the file, for exactly this kind of situation. <ieure>dodoyada, Have found Geiser rather barebones compared to SWANK or CIDER, though, so I don't know if it supports that. <ieure>Or if you're using Geiser, for that matter. <ArneBab>Is it intentional that (define-inlinable ...) does not support rest arguments? (define-inlinable (foo . rest) rest) ⇒ failed to match any pattern in form … <ArneBab>This currently skews the API I’m writing for define-typed, so I’d like to know whether this is done for a reason or whether it’s just an implementation issue. <identity>i doubt that a rest argument is a good idea in an inlinable procedure; the signature seems to imply that it is intended, the way i read it at least <civodul>ArneBab: maybe not intentional, but note that this macro is much less useful these days with cross-module inlining <ArneBab>civodul: it makes a huge difference in speed when you’re using it to restrict arguments following the optimization guide by dthompson <civodul>i mean it sure is useful in cases where the compilers would instead choose not to inline <identity>using case-lambda to eliminate the rest list is also going to make a huge difference <ArneBab>civodul: yes, in that case the inlining is strictly necessary due to domain knowledge :-) <ArneBab>identity: can case-lambda and inlining be combined? <identity>does not seem like that on the first glance, though i doubt there is a technical reason for that <ArneBab>So I can’t use it yet, but it would be a nice improvement to simplify writing performance-critical code. <dthompson>civodul is right that cross-module inlining makes define-inlinable less useful. it's still handy for when you want to force inlining, though. <dthompson>and variable length argument lists can easily prevent further optimization <dthompson>ArneBab: from the quick glance I took at your code recently, my gut feeling is that a sufficiently advanced define-typed would outgrow what define-inlinable provides <ArneBab>civodul: so now this is as fast as the hand-optimized code: <ArneBab>(define-inlinable (float? x) (and (real? x) (inexact? x))) <ArneBab>(define-typed (magnitude-typed x y) (float? float? float?) (sqrt (+ (* x x) (* y y)))) <ArneBab>dthompson: that would be pretty neat. <dthompson>forcibly inlining perf sensitive code is a hack I use to get around the fact that type inference happens local to a function <ArneBab>Just need to be careful that compile times don’t rise too much. <dthompson>what I would really want is compile-time type checks for a typed subset of the language <ArneBab>Don’t you use hand-inlined code? I switched to define-inlinable, because when I used a simple proc, I did not reach your performance with hand-inlined type restricting. <ArneBab>that you use define-inlinable, because you did not use it in the article :-) <ArneBab>I can’t offer compile-time, but all define-typed procedures carry their checking procedures with them, so an editor could recognize that and do typechecks during writing. <rlb>dthompson: very much want that too. <rlb>(wrt typed subset -- being able to just drop down to more explicit optimization "somewhow" easily) <ArneBab>⇒ evaluate the definitions in a subshell, then apply typechecks to the arguments and ensure that proc that use the output of other procs have the same typecheck for the input as the other for the output. <ArneBab>for the magnitude-typed above: (procedure-property magnitude-typed 'argument-types) ⇒ (#<procedure #{% float?-procedure}# (x)> #<procedure #{% float?-procedure}# (x)>) <ArneBab>and (procedure-property magnitude-typed 'return-type) ⇒ #<procedure #{% float?-procedure}# (x)> <ArneBab>together those should suffice to build validation for statically typed parts of the code in the editor. <ArneBab>(I think define-typed needs its own article and its own repository …) <dthompson>I think it would be possible to do some amount of what I want in "userspace", without touching the compiler or introducing a new language into the compiler tower <identity>last time i was doing this kind of thing, i just threw together a ‘where’ macro that was used like this: (where (real? x) (inexact? x)) and put it at the top of the function bodies, it expanded to something like (unless (and (real? x) (inexact? x)) (error "type mismatch" real? x inexact? x)). iirc common lisp's ‘the’ form does something like this <dthompson>there's a surprising amount of stuff you can do when you take advantage of the fact that syntax transformers are procedures and can thus have procedure properties placed on them that you can inspect *at expansion time* with syntax-local-binding <identity>if only duckduckgo was working, then i could actually check! <dthompson>but unfortunately I don't think anything short of compiler work can get us around the type inference limitations <rlb>dthompson: do you happen to discuss that in the optimization doc? (haven't gotten to read it yet) <ArneBab>dthompson: which limitations do you mean? Do you have a list of things you’d wish would work? <rlb>ACTION would read that too :) <dthompson>ArneBab: what I mean is that it ought to be possible to an uninlined magnitude-typed that still has optimized bytecode but has elided all type checks because the caller was known at compile time to be passing the proper types <ArneBab>dthompson: so basically caller-aware optimization? <dthompson>we're getting into "is this even scheme anymore?" territory <dthompson>but whether through an embedded DSL or a separate language in the tower, I'd like to write a small subset of my code in this way <ArneBab>I guess you’d need multiple versions of procedures, depending on where they were called. <ArneBab>I think Javascript does a lot in that direction, so wingo likely knows the tricks -- including the pitfalls. <identity>yeah, ‘the’ in common lisp lets you specify types of forms, though “The consequences are undefined if the values yielded by the form are not of the type specified[…]” <dthompson>I'd like a little more safety than that lol :) <dthompson>but CL has lots of cool type specialization stuff <identity>if it breaks, you get to keep the dust when it settles <dthompson>rlb: maybe a cursed macrology blog post is needed, then. <ArneBab>I guess something like (unless (float? a) (error "err")) (magnitude a a) ;; <- specialized magnitude that embedded the compiler knowledge that a is a float. <dthompson>I still need to see if r7rs-large's proposed identifier properties would make this an uncursed pattern because it would be properly supported in the macro system and not a hack <ArneBab>⇒ need to have a list of different procs in the compiler that have the same name but different argument guarantees. <identity>the racket folks do some cool stuff with typed racket (the type checking is done at expansion time iirc) <dthompson>I've never used typed racket but heard it was slow so I figured there was lots of runtime checking <ArneBab>I don’t like it there that they actually need their own #lang instead of providing define-typed -- to far from Scheme for my taste. <identity>it is slow if you interface between typed and untyped racket, but faster if you do not <dthompson>yeah once you are making your own language then you have all the flexibility you need to generate the code you want <dthompson>would be cool to have something truly embedded in scheme <ArneBab>ACTION is still happy that define-typed got more than 3x as fast as untyped for the magnitude-example by dthompson <Kolev>Not sure if this is heresy, but: Can a Rust cake be "iced" with Guile Scheme? <dthompson>technically I think it's possible if the rust can present itself as something usable by a C FFI <identity>sure, though you might want some of the scheme implementations written in rust instead <dthompson>and it's often inefficient in a different way due to the cost of crossing the FFI boundary <ArneBab>I wouldn’t mind linking to rust locally, but I don’t want to have to deploy that. <dthompson>and since it's not scheme, well now I can't run it everywhere my scheme runs <Kolev>I'm learning Rust and want to marry it with Guile, but that does sound ugly. <rlb>fwiw, you *can* use rustc directly to create a .so that'll just work via dlopen, etc., as long as you also make sure that all the rust functions are "extern C". <rlb>ACTION tested that wrt python some good while back <rlb>i.e. just put rustc in your makefile with the right incantation, etc. <rlb>but that's mostly useful, of course for computatio-heavy code. <rlb>I was looking at it for that purpose at the time -- didn't need deps. <rlb>(and mostly just curious) <rlb>Presuming the gcc support finally gets there, I'd be even more likely to be "at hand", I suppse. <ArneBab>Kolev: for maximum performance that used to be a best practice with Python, but I feel like the Py3 breakage pushed people more in the direction of "do everything in C++ and only build an interface in Python". <ArneBab>I helped people back at the institute (~9 years ago) to replace their old spectography code with Python + cython and actually reach the full speed of C <Kolev>Hopefully there will be Adwaita apps in Guile in the future. <Kolev>I got into Rust because it has good Adwaita support and lots of apps are written in it. <Kolev>A graphical Adwaita installer for Guix, written in Guile, would be nice. <identity>Kolev: be the change you want to see, as they say <Kolev>Yeah. Is Guix still a good package manager for Guile development? I'm hesitent to install Guix on Fedora on a Chromebook. Lots of disk space. <ArneBab>Kolev: yes, guix is pretty awesome for guile development. <identity>Kolev: most of the Guile projects i see use Guix, so <ArneBab>IT makes my chickadee-game dev convenient! <Kolev>I forget all that's needed to get Guix on Fedora, and I'm not sure it'd be worth installing it on a Chromebook, with its limited disk space. Guix hogs space. <ArneBab>I’m using Guix as main system; don’t know whether that’s possible on a Chromebook. <Kolev>I can't get audio to work on this Chromebook on Guix, so I stopped using Guix. <Kolev>Plus, I had to compile a kernel to salvage the hardware. <Kolev>I'll just not install Guix on my Fedora Chromebook. It's too heavy for my meager disk space. <Kolev>Wait, could I build the apps on my server that has Guix, then export it as a container and run it as a container on my Fedora system? <ArneBab>The documentation sounds like that, but I did not try it yet. <Kolev>Maybe that'd be a way of using Guix without filling up my Chromebook. <ekaitz>Kolev: come to #guix so we can talk about that better <euouae>If I write a guile program meant to be ran as a daemon e.g. by systemd, would there be issues with how guile compiles sources? <ieure>On the surface, those seem to be completely orthogonal issues. <euouae>would `guile mydaemon.scm` work? <ieure>Assuming it knows about the load-path for whatever else it needs, sure. <ieure>Why wouldn't you build a binary and run that, though? <euouae>No, I will do the latter. I wanted to understand what the right way is <ieure>I don't know if there's one "right way" to do what you want. I would recommend AOT compiling anything you want to run in a production-like setup, meaning, anything other than actively hacking on the code. <euouae>AOT? the daemon should be reloadable <euouae>The users should be able to script it <euouae>stuff in /etc/mydaemon/user_foo_module.scm <ieure>Why would users have write access to /etc/mydaemon at all? That's a gaping security hole. <ieure>I'd build it in such a way that a precompiled binary can augment itself with additional code. I'm not sure about Guile specifically, but this is a very normal Lisp feature. <ieure>ex. Common Lisp, you create an executable Lisp image you can reload, the image has the compiler and all that stuff, so you can load and compile new code at runtime. <euouae>I'd assume it's just an eval of the file? <dsmith>Guile is not like CL. You can't save an image. There is no compiled output (other than individual .go files) <dsmith>Years ago, guile *did* have an "unexec", but I think that evaporated when it became libeguile.so and started loading other .so <euouae>dsmith: so what is the advice on running a guile script as a daemon? <euouae>or should it simply not be done? just use C with embedded guile <dsmith>Just run it like you would any other guile application. For example, maybe check out GNU Shepherd on guix. <dthompson>yeah I've got guile in pid 1 on my laptop rn thanks to shepherd <dsmith>Someone here (for who) has (or is working on) a way to package guile with all the .scm and .go files into single executable file that knows how to get at the individual files as needed. <rlb>dsmith: believe it's mwette <rlb>maybe guile-saapp which may have become guile-freezer iirc <dsmith>Hah! mwette has more gray hair than I do. <euouae>Oh no I didn't ask to save an image <euouae>I just realized what you said above -- I think you missed the point <euouae>but ok maybe I'm not making much sense anyway, in my head it became clear now though <euouae>I'm probably going to write a policyd daemon for e-mail in Guile because I don't like what's availble. Thanks again! <omentic>heyo! how might i use ... within a syntax-rules within a syntax-parametrize? <omentic>when i try to use ... regularly i get an error about there being extra ellipses in the form. racket has the special (... ...) form to fix this exactly, but guile scheme doesn't seem to have that. is there an equivalent? <omentic>hm, is there an equivalent to racket (void)? <identity>omentic: as in an unspecified return value? <omentic>identity: yeah. i tried (if #f #f) since that's what tree-il's void says it's equivalent to, but it didn't work. <omentic>(if #f #f) errors with "wrong type to apply: #f". (values) errors with "too few values returned to continuation". <omentic>lemmie look at this closer, hrm. i guess racket (void) does some magic stuff. (values) feels like it should work. <dthompson>(values) is different from (if #f #f) aka *unspecified* <dthompson>the former produces zero values, the latter is one value <omentic>i do want zero values. this seems to not play nice with guile tho <omentic>i would like (simple-format #f "~a" (values)) [<- guile code] to work like (printf "~a" (void)) [<- racket code], essentially <dthompson>returning zero values is fine as long as the place it is returning to is prepared to accept that <omentic>interestingly (printf "~a" (void)) returns #<void>. so i guess maybe racket deals with #<void> as a special case or smth? <dthompson>a void/unspecified/null/whatever value is distinct from no values <omentic>ah, right. so (if #f #f) would be more what i want <dthompson>in guile, the unspecified value is bound to *unspecified* <dthompson>and yeah (if #f #f) is a weird trick that also produces it <identity>dthompson: i have seen people interpret “the return value is unspecified” in a way that makes (values) acceptable <dthompson>I like the idea of procedures evaluated for effect returning 0 values <dthompson>we have the flexibility of multi-values in scheme so we should use it, imo <dthompson>it can cause confusion, though, because most programmers are familiar with there always being a single return value <dthompson>so when the dreaded "Zero values returned to single-valued continuation" error shows up they don't know what's going on <omentic>blurgh, i can't tell if this "continuation" referenced is that or the actual continuations i'm papering over. time to macroexpand <omentic>it crashes with "wrong type to apply: #f". not sure why. i don't think it should. <ieure>omentic, The car of an unquoted form is #f instead of a procedure. <ieure>I don't know which, but that that's what the error means. <dthompson>'case' takes an expression and matches it against literals in its clauses (case 'foo ((foo) 1) ((bar) 2)) <dthompson>other than that, the code looks like it will for a list of a one element, but it fail with more than that because 'k' is not resumed from within the prompt <omentic>thanks a bunch... yeah i was using racket match and mixed up case/cond when moving it over