IRC channel logs
2026-09-23.log
back to list of logs
<mwette>I had an earlier version where the exports were not printed but collected in the seed. Then one could process all the exports at the end, saving runtime by reducing the number of `(export ...)' calls. <mwette>see commit 1e9b75c8c25f12da754e2023b09209271f413f10 <mwette>This was to address your issue w/ large number of exports IIRC but it got too complicated IMO. <dukester>Is guile much different from other schemes - chicken e.g.? <JohnCowan>mwette: I agree that the number of results returned by a procedure shouldn't depend on the values of its arguments, but I see no problem with procs that accept n args and return n+1 or 2n or n/2 results <old>I have a local branch where I am working on compiling .go file into Guile so that we can ship standalone executable <old>Ideally, I want to do without objcopy from binutils <old>I was wondering how is guile-freezer working ? <mwette>JohnCowan: I think I don't follow. I had a procedure that had a key-arg to determine if a `a' or `(values a b)' should be returned. good or not good? <mwette>old: Maybe one could use ffi i/f to libbfd. <mwette>or maybe the elf i/f in (system vm elf) <old>well I am working with (system vm elf) <old>My ELF knowledge is a little rusty, I will have to determine how I can slice into the guile binary a new data section <dukester>noob here. How different is guile from other schemes? <ArneBab>JohnCowan: do you mean something like SIMD operations or mapping math on the arguments? <ArneBab>looks like no one saw the question by dukester in time :-( <JohnCowan>I love that page, but I always tell people to read the comments too <JohnCowan>mwette: You wrote: "IMO, a function that returns mulitple forms for different inputs (i.e., single value or multiple values) is poor architecture. " <JohnCowan>I said I basically agreed with a caveat, and then you mentioned your procedure thst reurns 1 or 2 values depending on the value of its key argument, an apparent contradiction <ArneBab>JohnCowan: it would be great if we could move the opinionated list page into a wiki or such and enhance it with more opinions inline ☺ <mwette>I used "different forms" to differentiate <list> and (values <list> <list>). Hope that clarifies. <mwette>Is this "bad"? `format' returns either #t (IIRC) or a string depending on what the port argument. <lloda>it's a bit hacky but it's been like that forever <JohnCowan>it's to escape that type of hack that I wrote SRFI 189, Maybe and Eithery <mwette>JohnCowan: Nice. I have wanted that in times past (after being exposed to Rust). <lechner>Is it hacky to return different types? <JohnCowan>I would say yes except fir universally polymorphic functions like cdr. <mwette>I read somewhere once that procedures should be flexible on argument types, inflexible on return types. It makes sense to me that numbers are an exception. <mwette>and some others (e.g., pair refs as JC mentioned). <lechner>JohnCowan: I remember Maybe and Either from Haskell and liked them there, but are they really needed in Guile? Our variable return types are already Maybe's (with #f) and we also have exceptions, which I generally prefer for error conditions. <JohnCowan>lechner: Consider the find function, which searches a list and returns #f if not found, which does not allow searching for #f. <lechner>JohnCowan: OK. Thanks! I'm sure I'll find a use for your SRFI then. <lechner>The exception or the word ceremonious? <JohnCowan>java likes declarations like "Ship ship = new Ship" and claases named FooFactoryFactoryFactory <lechner>compared to Guile, I suppose, bug not to Haskell <JohnCowan>thats because Haskell likes operators like #$$±$$# <old>oh nice there's a SRFI for that <lechner>Yeah, I think LLMs are so successful because we made our programs too hard to read! <old>I might add it to guile <old>I often find myself with making API that accept a DEFAULT argument that will be returned on failure <old>and you need to check against this value <old>all that ceremony of defining a global (define nothing (list 'nothing)) <old>haven't check, but I do hope the SRFI works well with match like in Rust <mwette>I wonder if effient passing of values (like for call-with-values) for this srfi would need consideration in the optimizer. <mwette> yep, that one. Also possible to have a `nothing' (like Python's None), but not sure how well that works with the values protocol. <lloda>lechner: the hack really isn't the return type, but the overload on the type of the port argument. If (format #f fmt ...) is (sformat fmt ...) then the return type becomes consistent <lloda>overload on the value, I should say <mwette>I wrote a guile module for printf and decided to use a separate sprintf for string output. <dukester>Is guile much different from other schemes - chicken e.g.? <sneek>dukester, you have 1 message! <dukester>sneek: good read! Has guile solved its troubles alluded to in the article? <AwesomeAdam54321>sneek, later tell dukester: there have been developments since then, like being able to run Guile programs in web browser (via Hoot) <dyens>Hi! I'd like to make an HTTP request like this: <dyens>But http-get doesn't have a timeout argument, so it can hang for a long time (specially if some net issues). How can I work around this? <ieure>dyens, I don't see any mention of timeouts in any of the (web client) stuff, so I think there simply is no way to do this. <dthompson>timeouts make more sense when used with an async i/o system <dthompson>because then it's a choice at a point in the program: either return the response of this http request or return whatever if this timeout occurs, whichever happens first <ieure>I don't agree with that at all. Any time you're doing network stuff, you need to care about timeouts. Synchronous without timeouts is bad, because you block the program for an indeterminiate-but-typically-extremely-long period of time with no way to recover. <dthompson>my point is that you need some sort of event loop to do this properly <dyens>It can be solved by using non blocked socket with polling, but this is so low level... <dthompson>yes, you want your tcp socket to be nonblocking so you can use current-read-waiter <dthompson>the trouble is that (web client) abstracts this away from you, and I believe it predates all the async i/o stuff we have now <dthompson>so I don't have a good workaround besides copy the procedure source and modify it as necessary <loon>I haven't tried it myself, but the old standby of Unix signal handlers comes to mind as something of a last-resort option <dthompson>all the http-verb procedures have a socket arg <loon>yeah, do that instead of the signal handler :) <dthompson>and open-socket-for-uri has a socket-style arg so you can get set the nonblock flag <dthompson>*then* you can write a retry loop with a timeout <loon>in case you're curious how the signal handler approach would work, you'd use the alarm(2) API) and register a handler for SIGALRM <old>that's not re-intrant <old>you only have one alarm <old>you could use setitimer and friends <old>better just use fibers <dthompson>unfortunately fibers doesn't come with an async web client ready to go <dthompson>but yes with some work you can either use fibers or work directly with current-read-waiter and suspendable ports <dyens>Thanks, `socket args` in guile 3.0.11-1, i need to update <old>I would not work with 3.0.11 if I were you :-) <old>depending on your usage <loon>thank you for the note about the lack of re-entrancy, that's a good point :) <old>primitive-fork is broken. You can probably make it works if you only use spawn <dthompson>the #:port arg to http-get and friends has been in since 3.0.3 <old>perhaps you don't need any sub-process at all so that's fine <rlb>The other way of course is threads? (No idea if the web commands are compabtible) Ideally with full support for a virtual thread flavor too, but the latter requires a large amount of of work in the platform itself. <rlb>I just meant in general wrt async, IO etc. <dthompson>dyens: actually... I'm wrong. The #:socket-style arg to open-socket-for-uri is quite new. <dthompson>commit 2aace82aa67da75e0c10b8b2a58b688fb10ca00b <rlb>(i.e. just meant if the whole platform supports a virtual thread flavor all the way down, then you can roughly write straight-line code much of the time.) <rlb>(Though the only place I know offhand where that's the case is newer jvms.) <dthompson>does "virtual thread" differ in meaning from fiber? <rlb>It's a flavor of thread that's exactly like a "normal" (full system level thread) except that it can park, and the entire platform has to internally handle that "right". <rlb>i.e. if you call read() from a normal thread it'll block, but if you do it from a virtual therad, it'll park, etc. <rlb>(and of course all the internal IO, etc. has to be reworked to support that, I presume) <rlb>Actually, sorry, I should not have said "absolutely". You might be right. Realized I'm making too many assumptions about fibers. <dthompson>in guile terms, suspendable ports + continuations give you everything you need <dthompson>fibers is a useful abstraction on top that provides CSP-like semantics <rlb>At least on the JVM the main difference was that before, for asyncery, you had to (re)write your code. With virtual threads, I believe you can typically just switch which flavor of thread you create, and then of course you can create *far* more of the virtual kind. Among other things, it's a way "lots of threads" can compete with an event loop approach, e.g. (traditional at least) apache vs nginx. <rlb>(And all the existing thread support (data structures, concurrency tools, etc.) work exactly the same. mutexes park when needed, thread pools, all the synchronizers, etc. (jvm has some quite good bits on that front).) <dthompson>the fibers approach eschews the thread sync primitives in favor of CSP <rlb>Yeah, most of my work there has been with clojure, which provides safety via the persistent data structures and "atoms", etc. <dthompson>that is how you work with fibers as well. fibers share peristent, immutable data and retain exclusive access to mutable data <rlb>I suspect core.async (the norm there) is similar to fibers, though it's switching internally to drop the state machine I think, etc. in favor of the new virtual thread. <rlb>And via core.async, I used channels a good bit. <dthompson>fibers is built on delimited continuations so no (explicit) state machine <rlb>Basically, I think (the jvm's flavor of) virtual threads pushes at least some of the hard work down into the platform. <rlb>Right, scheme is fancier ;) <dthompson>it sounds virtual threads are sort of continuations but not as flexible <rlb>Oh, well of course nothing else is that flexible? :) <dthompson>continuations are the lower level primitive, yeah :) <rlb>I think there's probably some practial benefit (as compared to maybe python/ruby/etc.) for what the jvm has done, since it's all integrated, but I also assume it was a *lot* of work. <rlb>i.e. you just don't have to think about it (much) --- all the existing documented calls for "all of the things" just work the same. <rlb>(and there's a *lot* and a lot of existing code) <rlb>But sometimes you park and cost a lot less than others. <dthompson>you can make the say e.g. port reads/writes that that you do in blocking code but instead it suspends the current continuation <rlb>Oh, and all the fancy thread pool infrastructure is still there, so you can trivially create a pool of N real threads backing all of the virtual threads created from it, I think. <rlb>As long as other code/libs/etc. don't have to be adjusted to interoperate with fibers, then yeah, might be similar there too. <dthompson>the equivalent of that in guile would the fibers scheduler. it distributes fibers amongst some number of pthreads <dthompson>fibers was inspired by ConcurrentML, but goroutines are more or less CSP, iirc <lechner>Hi, mwette wrote in another forum that Guile package files may be installed directly into the "site" folder and do not have to be placed in the versioned folder below it. It makes sense even though I had not seen that before. Is it true? <rlb>dthompson: hmm, so with fibers, guile itself probably has to add "relevant" support for anything that can block at th OS level (like suspendable ports)? And I guess that means that unless guile eventually only offers suspendable ports, it's not quite the same, i.e. if you call some library function that returns a non-suspendable port, you can get stuck? <dthompson>lechner: files should be installed to the versioned site directory <dthompson>guix's search path configuration for guile does not include the non-versioned directory, for example <dthompson>multiple versions of guile can be installed in parallel <rlb>Though if that's right, were we to effectively pull fibers into guile, we could probably (with perhaps a lot of work) make it similarly integrated, which sounds pretty good to me, conceptually. <dthompson>rlb: the reason why suspendable ports are opt-in currently is because of the performance differential. <mwette>%load-path includes both ".../guile/3.0/site" and ".../guile/site" I've used "site" for cases where I have multiple versions (e.g., 3.0, 2.2) installed. <mwette>So I only have one copy of, say, bytestructures installed. <lechner>mwette: For Guix, the GUILE_LOAD_PATY is much longer because different package versions are in the store <dthompson>are we talking only about source files, or source and bytecode? <lechner>mwette: but I agree with you in principle <dthompson>on guix specifically, there's only one correct place: versioned directory <mwette>.scm files; the compiled parts go in separate version-specific dirs <dthompson>lechner: so you could have different versions of the library installed for, say, both guile 2 and 3 <dthompson>guix has variants of packages for different major versions <lechner>dthompson: mwette's argument is that the module is low level and therefore universal <lechner>but I don't always use the .go files, so it does not work for me <dthompson>because that property is not true in general <mwette>I can change my install scripts, with a little more complexity, but if incorrect, why is "guile/site" there at all? <dthompson>that I don't know. may be legacy reasons because guile didn't always support parallel installs <lechner>dthompson: Thanks for confirming, by the way! <mwette>well, on my laptop, guile -c "(display %global-site-dir)" => "/opt/local/share/guile/site" <rlb>/usr/share/emacs/30.2/site-lisp <rlb>/usr/share/emacs/site-lisp <dthompson>yes I know that it's there. but iirc the conversation was started due to a guix packaging issue. <mwette>oops (display (%global-site-dir)) but I see there is also %site-dir. <dthompson>so 1) installing to the effective version directory is generally best practice, though not required on all systems 2) guix requires installing to the effective version directory <rlb>Sorry, wasn't commenting on the broader issue, just perhaps wrt why guile might have it. <dthompson>someone that isn't here surely knows the historical answer :) <mwette>I'll change it, but that bumps the major version by semver, I guess. <dthompson>alternatively, the guix package can just patch it <JohnCowan>Timeouts are important even if you are not using concurrency: if you are refreshing resources one at a time, it's better to be able to abandon attempts that take too long than to hang the whole process. <mwette>I believe lechner has provided a patch for that solution. <lechner>mwette: Can you get someone to accept it? No attribution needed. <mwette>I think you need to create an issue. IIRC you proposed that patch on a closed merge request. <lechner>mwette: Unfortunately, that's a waste of tume. They have not dealt fairly with my contributions, so I'll use your package from my personal channel. Please feel free to direct the Mes folks to my patch, however, when the time comes. <mwette>lechner: Thank you. In the meantime, I have released v2.0.0 on github. MES will not be using guile-cdata as far as I know. I have provided then a separate stripped down nyacc for their purposes (github / mwette / nyacc-for-mes). <lechner>You're the most accommodating upstream I know. <mwette>It was claimed here that what you asked for is a guix constraint. <mwette>I hope the bazel people never discover my stuff :) - bazel is a nightmare. <lechner>No, I mean why did Mes ask for a stripped-down versions? <mwette>They did not ask for that. I gave it to them so I don't have to worry about being mes-compatible (e.g., using vlists, syntax-case, etc). Also, they are interested in speed, so I converted some syntax-case / syntax-rules forms to define-macro, added hash tables (where I used vhash in 4.0), removed source-tracking, ... Ended up reducing the C parser execution time (in guile) by 80%. <lechner>mwette: Why is it not suitable for general use? <lechner>mwette: Also, would you be at all open to patches that might bring the FFI helper and my procedural interface in guile-import-cdata closer together? I got rid of all global variables to make it easier to reason about it. <mwette>Maybe, need to see it. I want to reduce the time I spend on c99 and ffi-helper right now and get back to my other projects. <lechner>mwette: Also, I rely so extensively on Nyacc that I effectively forked the FFI Helper. I could potentially be motivated to help with the latter, but not with the parser. <mwette>I think I messed up guile-cdata v2.0.0 <lechner>That's if you and I can get over our creative differences. <lechner>It's okay, I may not upgrade until other features appear in CDATA. I just generated the kernel and Glibc bindings on 12 architectures. <lechner>I guess I'll upgrade CDATA once I figured out my migration to Nyacc 4.0.0 <lechner>I can also test your CDATA commits here and now <mwette>lechner: thanks again; congrats on the kernel bindings