IRC channel logs

2026-04-10.log

back to list of logs

<czan>Are there any libraries for property based testing in Guile? Particularly including shrinking of generated data? I started working on one the other night, but if there's prior work (in Guile specifically) I'm unaware of it.
<yarl>Hello. I am working on https://codeberg.org/guile/guile/pulls/152#issuecomment-12923214 . Questions : Why srfi-9 defines (exactly the same) default-record-printer as boot-9 and is it possible to remove the definition from srfi-9 and boot-9 to export his or something like that? Would it be ok then to do something like (eq? default-record-printer (struct-ref vtable-index-printer RECORD)) to check that the record has t
<yarl>he default?
<yarl>Please tell me if I'm not going in the right direction.
<dsmith>!uptime
<sneek>I've been aware for 18 seconds
<sneek>This system has been up 5 minutes
<dsmith>(power glitch)
<old>czan: there is guile-quickcheck I think
<dsmith>sneek, software?
<dsmith>sneek, guile-software?
<sneek>Someone once said guile-software is http://sph.mn/foreign/guile-software.html Send an email to tantalum, <sph at posteo dot eu> to make changes or post a new project.
<yarl>Hey old, are you available?
<old>yes
<yarl>Did you have the chance to look at my questions above?
<old>oh
<yarl>I'm starting to think on the "opaque" thing now.
<yarl>I am a bit troubled by the fact that the documentation (7.6.2.8 R6RS Records) states "the various predicates and introspection procedures defined in ‘(rnrs records introspection)’ will behave as if records of this type are not records at all".
<old>the code seems to be duplicated but that's because Guile has records that are not specifically srfi-9 records
<old>and to avoid boot-9 having to have a dependency on srfi-9
<old>the definition in boot-9 is not at top-level to avoid polluting the namespace I guess
<yarl>Well, is that really pollution?
<old>anything define top-level in boot-9 is available everywhere. We don't want that
<yarl>To be honest, I thought implementing this was going to be an easy plug. It's becoming big.
<jcowan>yarl: Opaqueness lets you implement things as records that aren't actually primitive. A bignum could be a record, and you don't want to let people introspect on it.
<old>well wrt the custom printer, I think the solution is simple here.
<old>Well, maybe not because of boot-9 records ..
<yarl>jcowan: but you can only import (rnrs records syntactic) and the functions in boot-9 let you see what's in there (if you don't import (rnrs records inspection))
<old>but at least for srfi-9, I guess it would be possible to change the behavior of the default printer
<old>so that it detect its in "pretty context"
<yarl>old: Oh I see
<old>but then you would need to define a parameter
<old>and not sure where we want this define
<czan>old: Thanks! Do you know if guile-quickcheck does shrinking? From a brief look at the code I think "no", but I'm not sure. The example in https://ngyro.com/software/guile-quickcheck.html isn't minimal, though.
<old>like I said, better avoid adding new top-level binding
<old>czan: define shriking? Like finding the minimum set of inputs to cover all cases?
<yarl>old what about a property on the default printer?
<old>yarl: that could do it
<czan>I also saw https://srfi.schemers.org/srfi-252/srfi-252.html, which seems pretty hard to make work with shrinking, given the constraints it places on generator functions.
<old>I guess a printer could provide a pretty variant of itself if needed
<old>so the defualt printer could have an object property 'pretty-print which would be a second print function
<czan>Shrinking is taking a failing input and trying to make it "smaller". So if you generate a list of elements, shrinking might mean trying to remove elements and see if it still fails.
<czan>The idea is to improve the signal:noise ratio of the randomly generated inputs which provoke a failure.
<old>czan: Ah I see. I did tried something along like this before hmm. My idea was to provide a lib where you can specify a grammar with rules. Rules consume states and produce values. Anyway, then you can run the generate input and use a reducer to prune node in the generated AST
<old>If you know Csmith and Creduce, that's what I'm aiming for
<old>mostly for finding compiler bugs
<old>but I guess wrt to properties, it could be easier than that
<yarl>old: I'll look into it. I have another tiny question. The documentation says (rnrc records syntactic/procedural/inspection (6)).
<czan>I'm not familiar with that, but I'll do some reading. There are three common approaches in other PBT tools: one is type-directed shrinking (like Haskell's QuickCheck), one is generating "shrink trees" instead of just values (like Haskell's Hedgehog, or test.check in Clojure), and a third is a smart way of shrinking the random input stream (like Python's Hypothesis).
<yarl>Why the (6), you can't use-modules on this form.
<czan>I've implemented the shrink trees approach in a few dynamic languages (and now have a Scheme implementation that I'm considering developing further), but I don't want to do work to polish something if someone else has already built it. :)
<yarl>"unknown location: source expression failed to match any pattern in form ((rnrs records syntactic (6)))"
<yarl>Is it a documentation bug?
<old>czan: AFAIK nobody have
<old>if you are interested:
<old>- Csmith: Random C program generator https://users.cs.utah.edu/~regehr/papers/pldi11-preprint.pdf
<yarl>ooh, my bad
<yarl>7.6.2.1 Library Usage
<old>czan: and creduce: https://users.cs.utah.edu/~regehr/papers/pldi12-preprint.pdf
<old>they also did provided something in racket that's generic IIRC
<old>czan: https://docs.racket-lang.org/xsmith/index.html
<yarl>oh but the documentation in RNRS Records says "introspection" when it's "inspection"
<yarl>I'll fix that.
<czan>old: Thanks for that. Looking through the Creduce paper, their Seq-Reduce approach seems the most similar to what I'm used to from PBT. Although it's less sophisticated than what you can get with shrink trees (which can "remember" how they're constructed and shrink appropriately).
<yarl>old, a last question, may I? On the opaqueness. It's confusing, I think, that you might only import syntactic, define an opaque record and use (base) record? and it and it says #t.
<yarl>While if you had also imported inspection, it would say #f.
<yarl>See what I mean?
<yarl>Shouldn't base record? say #f on RNRS record, either opaque or not?
<yarl>same reasoning on srfi-9 record? by the way.
<old>yarl: I've never used opaque record myself so ...
<old>let me check
<old>record? from rnrs add to record? from boot-9
<old>it also check that it's not opaque
<yarl>The same the other way around. I define a record with srfi-9, (format #t "~a~%" ((@ (rnrs records inspection) record?) foo)) says #t
<old>the core record? works for any struct
<old>guile has no concept of opaqueness
<old>it's a rnrs thing
<old>because srfi-9 record are guile record AFAIK
<yarl>But I have no way to distinguish between rnrs and non-rnrs records.
<yarl>I'm near to giving up on this PR.
<old>hm
<old>well no the correct way would be then to define a custom printer for opaque record?
<old>so that it's does not leak anything
<yarl>aw again right. I think the wrong way.
<yarl>Even if I don't manage to go through this, I learn.
<old>but also you have record-type-opaque? define in boot-9
<old>so actually it seems Guile do understand opaque records
<yarl>oh
<old>so I think you should do the following:
<old>1. If the record type has a pretty-print object property, call it.
<old>2. If the record type is opaque, print something like <type> only
<old>3. Fallback to just write, which will call the custom printer in place
<old>you mind have some circual things going on there wrt to 1. tho
<old>So I don't know what would be the best approach here
<old>you could make the object-proprety a flag that's #t by default. If a user set a custom printer, you set that flag to #f. Use that flag in the pretty-printer to make a decision
<old>the ideal thing would be to know if the printer is the default one, but anyway
<yarl>right.
<ekaitz>i posted some scheme implementation question on my mastodon, if anyone wants to join and teach me some programming
<ekaitz>it's basically me having architecture questions for GNU Mes and its Guile compatibility
<ekaitz>and how should the evaluator be fed with expressions to evaluate
<old>ekaitz: I don't have this social media :(
<ekaitz>no need! my profile is open
<old>link ?
<ekaitz>let me link you to the video directly: https://cdn.elenq.tech/Scheme_Driver.webm
<ekaitz>ACTION has to go, but will be very happy to discuss about that via email, in a meeting or anything
<avigatori>Hello o/
<avigatori>I was wondering what patterns schemers use instead of enums? Specifially in the sense of "I expect these cases to happen". Right now I have a module defined where I list all the cases that I expect as individual symbols. However, because of symbol interning the module is a bit useless.
<avigatori>I also like this pattern in other languages, because I can define the cases in one place that's authoritative. Maybe my brain is thinking too statically ...
<jcowan>avigatori: Symbols, basically.
<ieure>avigatori, Have you looked at rnrs enums?
<jcowan>But there is also the (rnrs enums) library, which wraps it
<avigatori>I had not seen the rnrs enums, but they seem to use list operations under the hood, which I wanted to avoid.
<avigatori>jcowan, would you basically just wrap the cases with a collection?
<ekaitz>avigatori: symbols and match is the way I've seen the most
<jcowan>yes, match is suitable for this
<avigatori>Is there a way to define methods/procedures on a record that are not field related?
<ieure>avigatori, I do not believe so. Sounds like maybe you want GOOPS?
<avigatori>Thank you ieure, I will look into that. I thought I had read that GOOPS is not encouraged anymore. Maybe I am mixing something up ^^
<ieure>I don't know if it's encouraged or not.
<rlb>avigatori: I'd say goops is just fine if/when you need it, and/or are OK with the extra cost.
<avigatori>Another thing: https://paste.debian.net/hidden/87f6da68
<avigatori>I wanted to override the "made-lexer" procedure, because some fields always have the same initial value and it would be nicer if one just had to provide just one parameter to initialize the record with. However, I wasn't sure how to do this. So I created a "build-lexer" proc instead. Tho it would be nice if I could reuse the "make-lexer" name
<avigatori>*make-lexer
<mwette>avigatori: the convention I've seen is to use %make-lexer in define-record-type and then define make-lexer to call %make-lexer.
<avigatori>mwette: what does the % stand for here? No export? (I know it's just convention)
<ieure>avigatori, % prefix usually indicates a constant value.
<avigatori>thank you!
<mwette>see system/vm/linker.scm for examples wrt record types
<ekaitz>avigatori: for methods/procedures for records what I do is write a separate procedure that looks like its of a record
<ekaitz>i mean if your record is a `piece` you can (define (piece-name piece) (...))
<avigatori>ekaitz: do you replicate the typecheck too?
<ekaitz>from the outside it doesn't matter if it is defined in the record definition or not
<ekaitz>if you want, you can
<ekaitz>you can also write a macro for it
<ekaitz>i just read this before and it's somewhat related: https://jointhefreeworld.org/blog/articles/lisps/functional-repository-pattern-in-scheme-with-macros/index.html
<ekaitz>i think about scheme records like C structs
<ekaitz>they have the data, but all the functions are not "in" them
<ekaitz>you can make a module, keep some of the getters and setters hidden, and expose other procedures that look like setters and getters but have other checks, for example
<avigatori>thank you ekaitz
<ekaitz>avigatori: please, ask further if you need, I can give some examples, too
<n|Phreak>Whats a good app for g-golf that interfaces with the internet ? Thinking about using g-golf to create some apps
<mwette>avigatori: I have used assert's in code like this: https://codeberg.org/guile/guile/src/branch/main/module/srfi/srfi-43.scm#L63
<mwette>here: https://github.com/mwette/nyacc/blob/main/module/nyacc/foreign/cdata.scm#L679
<avigatori>thank you mwette, interesting
<avigatori>another topic: maybe I am missing it, but is there a way to set a breakpoint for a non-erroring procedure?
<ekaitz>avigatori: non-erroring?
<ekaitz>in the repl you can break-at-source
<ekaitz>but all the breakpoint thingie is also available from scheme
<avigatori>heh, either my google foo is getting worse or google's search results
<avigatori>anyway, thanks
<ekaitz>i'm finding more interesting these days just search in the docs
<ekaitz>open in one file and ctrl-f
<ekaitz>or `info guile` and search there
<mwette>I have worked on something similar to pdb.set_trace() from python: https://github.com/mwette/guile-jtd
<mwette>ekaitz: maybe have the macro expander call `primitive-eval' that only works w/ a fixed set of primitives (e.g., _lambda, _cons, _if, ...) but which is a subset of operations that work on your stack-based.
<ekaitz>hmmm
<ekaitz>i'm seriously thinking on writing the "main" in scheme
<ekaitz>compile that and launch from there
<ekaitz>if the macro expander is written in scheme, then I could rewind to it
<ekaitz>the evaluator should only run once
<old>ekaitz: I did not had a change to view your video yet
<old>and I guess it will have to wait until next week unforutnatelly but
<old>until then, I would like to know quickly do you have the relevant bits of GNU mes interprator so I can look at it?
<old>and is it a bytecode interpreter or is it traversing the AST directly?
<ekaitz> https://codeberg.org/ekaitz-zarraga/mes/src/branch/modules
<ekaitz>well, it was a tree-walk interpreter
<ekaitz>now it has become a bytecode interpreter
<ekaitz>(basically that's my job, to make it a bytecode interpreter)
<ekaitz>for that, i separated macro expansion to a different step, and then rewrote the evaluator to first "eval-core" which only knew about basic scheme constructs, and then to "eval-compiled" which only knows about bytecode
<ekaitz>the process is cool and all that but there's an issue: calling eval, load, apply and such call a new instance of the evaluator on top of the one that it was running
<ekaitz>that makes top-level continuations impossible
<ekaitz>(in chibi, there are no top-level continuations, so it is ok in a way)
<ekaitz>in the fediverse some person has suggested that the issue is that I rely too much in C
<ekaitz>(which was obvious, but not *obvious*)
<old>that's because your evaluator is in C I guess
<ekaitz>i'd say that is because my macro expander and my driver are in C
<old>Guile has this minimal C evaluator for bootstraping the Guile evaluator which use the Guile stack which is more flexible
<old>oh
<ekaitz>i'm playing now with the idea of moving the driver to scheme, and then compile it and call the evaluator on it
<ekaitz>that should *never* leave that evaluator call
<ekaitz>which makes simpler continuations
<ekaitz>and hopefully 0 gc issues
<ekaitz>(this might mean having to write the whole macro expander again in Scheme, but if I managed to write it in C, it shouldn't be that hard now)
<old>so question
<old>why are you not using psyntax from Guile directly?
<ekaitz>uh
<ekaitz>great question
<ekaitz>probably janneke has more thoughts but I'd say it's a bootstrappability issue
<old>well I think psyntax need to be written by itself IIRC
<old>we have psyntax-pp which is the expanded psyntax
<ekaitz>GNU Mes is not just a scheme implementation
<old>and you probably need the original psyntax-pp written by hand if you want bootstrap
<old>I think
<old>Right I figured :p
<ekaitz>it is a fundamental project in the auditable full source bootstrap...
<mwette>Will you save compiled bytecodes to files (during a build session)? If you compile 100 times you don't have to recompile mescc each time.
<ekaitz>if we use psyntax-pp, we are basically not bootstrapping
<old>why not? If psyntax-pp is auditable
<old>ofc, I would not call this auditable right now
<old>it's 3400 line of spaghetti code
<ekaitz>old: instead we start from define-macro
<ekaitz>and we work our way up to syntax-case and all that
<old>is syntax-case working in Mes now?
<ekaitz>i think so, yeah
<old>nice
<ekaitz>it's not amazing, but kind of works i believe
<ekaitz>mwette: that's a great question and the answer is not at the moment
<ekaitz>but we could take a look into that
<ekaitz>compilation is *very* fast though
<ekaitz>samplet made some expander, too
<ekaitz>popsyntax
<ekaitz>that is very promising
<ekaitz>ACTION is very happy to engage in this kind of conversation forever
<ekaitz>personally i'm interested on making Mes easy to understand
<ekaitz>so that's also part of my goals, and I'm not sure if having a pre-generated file helps with it
<mwette>IMO, simple is better here: no syntax case, maybe stripped-down syntax-rules, single thread, simplistic module system (if at all?).
<ekaitz>yep!
<ekaitz>the module system is guile's and it's tricky and a lot of fun
<ekaitz>but still, very cool