IRC channel logs

2024-01-31.log

back to list of logs

<dthompson>is there a set of predicates one can apply to an argument that is expected to be an inexact real so that the compiler will unbox it as an f64? I thought (and (real? x) (inexact? x)) might do it but it doesn't seem to work.
<dthompson>perhaps it's just not implemented but I've seen the type inferencer figure out some pretty neat stuff before
<dthompson>like if you gate a branch with exact-integer? and then divide the compiler will optimize it to a right shift rather than using generic division
<mwette>in 3.0.9, language/cps/specialize-numbers.scm, line 809
<dthompson>thanks I've been looking in the cps code but I haven't found a clear answer.
<dthompson>it doesn't seem like what I'd like to do is currently possible
<dthompson>that specialize-numbers code happens after boxing/unboxing primcalls are generated
<dthompson>the only reliable way I know of to use unboxed floats is through bytevectors
<dsmith>dthompson, That kinda vaguely sounds familar
<dthompson>seems scm->f64 only happens for bytevector sets
<old>is there something in core guile for comparing semantic versions?
<old>I see there is guile-semver
<dthompson>correct me if I'm wrong but I think semantic versions can be compared with simple string comparisons like string<?
<dthompson>well maybe they can't. I don't remember if they sort lexicographically...
<dthompson>maybe ignore me :)
<old>hmm
<old>I mean, I could parse them, nothing hard
<old>but I suspect that there are corner case in semantic versioning
<old>like release candidate (rcN)
<old>I could just copy guile-semver in my project that ought to work :-)
<dthompson>I know guix has code for version number comparison
<dthompson>old: https://semver.org/spec/v1.0.0.html#spec-item-4
<dthompson>that's about pre-release suffixes but
<old>right guix/utils.scm
<dthompson>I think this shows that some additional logic is necessary and lexicographical order isn't enough in general
<old>right I'm more interested by comparing modversion from pkg-config
<old>right. we manage to make a mess even with versioning
<dthompson>for example (string<? "1.0.0-alpha1" "1.0.0") is #f but 1.0.0 is considered the greater version
<old>hmm guix use strverscmp from glibc
<old>interestring
<dthompson>ah right
<dthompson>that rings a bell
<dthompson>been forever since I looked at that code
<old>that ought to be in Guile core I think (strverscmp). It is a neat thing but a GNU extension to libc
<old>in the mean time, using the FFI is enought for this
<dthompson>yeah sounds like the easiest route for now
<old>thanks for your inputs!
<dthompson>this is unrelated to the above discussion but to put a bow on the question I asked last night about unboxing floats...
<dthompson>guile 3.0.9 does not do what I expect, but guile built from main *does*
<dthompson>guarding the relevant code path with 'real?' and 'inexact?' predicates leads to unboxed floats on main, which is just great
<dsmith>Also lexically, (string<? "1.2.0" "1.10.0") => #f
<dthompson>yeah
<dthompson>gotta parse and such
<dthompson>it's not like YYYY-MM-DD dates
<old>dthompson: what's float unboxing?
<old>I suppose it has something to do with bytevector?
<old>and game engine?
<dthompson>guile allocates certain numeric types on the heap, including floating point numbers.
<dthompson>if you do (+ x y) and the result is a float, a new float is allocated on the heap
<dthompson>the number is "boxed" inside of a heap object
<dthompson>unboxing is a compiler optimization that will take a value out of its box, run some number of additional instructions with it, and only box the final result.
<old>ah okay and so you want the raw bits of the floting point?
<old>thus unboxing
<dthompson>if you have a complicated math routine, this will avoid the intermediate values being boxed and thus allocated on the heap
<dthompson>it improves efficiency because specialized instructions built for specific types can be used rather than generic ones that need to operate on all types
<dthompson>and it allocates less, so less gc pressure
<old>Right. But the compiler optimization is not already all that?
<old>Or is it limited
<dthompson>that's what the optimization does
<dthompson>since scheme is a dynamic language, you need to be aware of this when writing code so you can give the compiler the information it needs to perform the optimization
<old>ahh I see
<old>you need to give hint to the compiler by guarding the critial path with predicate
<old>so the compiler can be sure that the values are of a certain type
<dthompson>right
<old>in another word, a typing system could do the same
<dthompson>yes
<old>and so GOOPS ought to do the trick here
<dthompson>no
<old>why not? Because of indirection and dispatching?
<dthompson>goops will make things more generic, not less
<dthompson>yeah
<old>right
<old>but my point is that GOOPS will do the predicates and dispatch to the correct version. And if this version is specialized, then it could be optimized
<dthompson>in a statically typed language, you could say that function argument 'x' is a float or something
<old>and so you remove the predicates from your code and encode them as type symbols
<dthompson>but that would all be at runtime
<dthompson>and the boxing would have to happen at each intermediate step
<dthompson>you don't need goops to do what you are saying. the scheme numeric tower already works this way.
<old>ah right
<dthompson>all of the math functions are polymorphic
<dthompson>which is great most of the time
<dthompson>but for critical paths you want to constrain your inputs so the compiler can specialize.
<old>right
<old>is it fast enough tho? I mean even with the compiler optmization
<old>or is it better to call C for that?
<old>even though there is a cost to call C
<dthompson>it's plenty fast enough for me
<dsmith>ISTR that r6rs introduced "fixed" or "float" or something operators. Supposedly for not having to dispatch on the type?
<old>what's your use case?
<dthompson>using the ffi would be faster if you were offloading a huge operation that outweighs the ffi overhead
<dthompson>but personally I want to keep writing scheme, not c :)
<dthompson>my use case is realtime graphics
<old>ofc. Right scheme and only C when you really need low-level optimization
<old>ray-trace?
<old>or rastering?
<dthompson>raster
<old>CPU based? damn
<dthompson>no
<dthompson>gpu
<old>in Scheme ???!
<dthompson>but you need to do a bunch of work on the cpu so that you have something to send the gpu
<old>That would be neat lol
<old>right right
<dthompson>all sorts of linear algebra is necessary to prepare a frame for the gpu
<dthompson>lots of vector and matrix math
<old>Right with the camera
<dthompson>with everything. positions of objects. their velocities if they are moving. their hitboxes for collision detection.
<old>hmm yes yes
<old>I guess you do not have millions of positions to compute
<old>I would assume that Scheme you be on its knees for that
<old>s/you/would
<dthompson>with compiler optimizations + jit things can go quite fast
<old>does the JIT generates SIMD instructions?
<dthompson>I've been able to render upwards of 50k dynamic sprites at 60fps
<old>nice
<dthompson>no simd currently
<dthompson>that would further improve things
<dthompson>but even without simd things are quite good
<old>I wonder one thing tho
<old>if you compute tons of positions. Are they all allocated close together?
<old>Because if they are allocated on the heap, then cache locality is not good at all
<dthompson>it depends.
<old>well if you do a huge allocation but that's about it
<dthompson>being on the heap doesn't necessarily mean cache locality is bad, though
<dthompson>all depends on the gc.
<dthompson>I suspect the upcoming whippet gc will have improvements there
<dthompson>but when I need locality I just allocate a big bytevector
<old>But then you need to heap allocate a boxed float for each in the bytevector?
<old>then write the result back in the bytevector?
<dthompson>nope
<dthompson>bytevectors are raw memory, basically
<old>or is there a way to tell guile: ASsume the following memeory to be a float and mutate it
<dthompson>bytevector accessors work with unboxed values
<old>I know there's bytvector-*ref getters
<old>But I always assume they returned a copy of the underlying bytevector or something like that
<dthompson>for example, (bytevector-ieee-double-native-ref bv 0) will produce an f64 that will only get boxed if it needs to be
<old>and how do you change the underlying value in the bytevector?
<dthompson>a lot of my linear algebra code boils down to pulling floats out of bytevectors, doing some math, and stuffing the results in another bytevector
<old>Will the operation on the result of (bytevector-ieee-double-native-ref bv 0) be reflected directly?
<dthompson>the bytevector-*-set! procedures
<old>ahh okay
<old>so it does a copy and you write it back
<old>make sens
<dthompson>example: (bytevector-ieee-double-native-set! bv 8 (* (bytevector-ieee-double-native-ref bv 0) 2.0))
<dthompson>gets an f64 from index 0, doubles it, stores it to index 8
<dthompson>no allocation would happen here
<old>the intermediate value is copied onto the stack?
<dthompson>yes but unboxed
<old>neat
<dthompson>the multiplication would be done with fmul and not generic mul
<old>where did you learn all of this? This is not in the manual AFAIK!
<dthompson>years of messing with guile and asking questions in this irc channel
<dthompson>I have a list of "blog posts I'd like to write" and a guile optimization post is on the list
<old>nice!
<old>sounds interestring
<dthompson>I used guile before any of these fancy optimizations were around
<dthompson>not jit compiler, etc.
<dthompson>so I ended up learning the hard way why things were slow
<old>I guess all dynamic language were kind of slow at some epoch
<old>certain are still very slow -- looking at you CPython --
<dthompson>some are kind of doomed to be slow due to their semantics like python
<dthompson>and ruby
<dthompson>scheme compiles real good
<Arsen>ruby's extremely dynamic, yeah
<Arsen>py can static-type sometimes at least.. that constrains it heavily and could enable some optimizations if cpy was to make use of it (which I doubt will happen any time soon)
<old>and yet they are more popular :-(
<dsmith>Popularity is overrated. "10 billion flies can't be wrong, can they?"
<old>true
<teddd>hi guiler, I was wondering if someone knows about a lib to parse config files like .ini or the like ? Alternatively is there a templating library in guile similar to jinja in python ?
<dsmith>sneek, guile-software?
<sneek>Last time I checked 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.
<dsmith>teddd, take a look there ^^
<dsmith>There is guile-ini https://github.com/artyom-poptsov/guile-ini
<dsmith>Scheme mostly (ab)uses quasiqote for templating I think.
<teddd>dsmith: thanks for the reference !
<dsmith>There is the sxml stuff to create html and xml from s-expressions
<teddd>Yes most lispers just prefer lisp as data structure. Understandable. But I need to extract data from the rest of the world :)
<teddd>Oh yes sxml looks nice. I'll definitly use it if I do we in guile
<teddd>For now I just want parse config files.
<teddd>dsmith: There is also guile-config https://gitlab.com/a-sassmannshausen/guile-config
<dthompson>teddd: I'll pile on to say that a lot of scheme programs do the "configuration as code" thing and do not use a separate config language.
<Arsen>ACTION would do so too
<teddd>dthompson: Yes I also do it like this when I stay in lisp world.
<teddd>dthompson: btw I just came across your guile-parser-combinator https://git.dthompson.us/guile-parser-combinators/tree/README
<teddd>I thought about using it to parse conf files. Would you recommand ?
<dthompson>teddd: that was a little experiment. it's not a properly packaged library or anything.
<dthompson>it's using streams which are cool but slow.
<teddd>dthompson: I see looked promising and easy to use :)
<dthompson>I like parser combinators, you should feel free to snarf any of the code there
<dthompson>streams make the code pretty nice, but it's not going to perform nearly as well as using ports directly
<ieure>parser complicators
<teddd>dthompson: cool, I'll take a look, though I'll probably not find time to push it further
<teddd>ieure: ^^
<dthompson>for .ini files, guile-ini already exists as mentioned above
<dthompson>you can also do s-exp config that isn't executable scheme code by just using 'read'
<teddd>Yes I the guile-ini would be great, unfortunatly I realised I really need something more flexible and add things to a lot of different file formats. I guess I would need something like a templating framework linke jinja or noweb
<dsmith>I don't understand. Aren't templating frameworks for *writing* files?
<dsmith>Anyone remember brl?
<dsmith>Beautiful Report Language
<dsmith>Was a pretty cool idea. Added ] [ as string delimeters. And a file started out in string mode.
<dsmith>lots of text [(scheme expression)] back to text...
<dsmith>expands to: "lots of text " (scheme expression) " back to text.."
<dsmith>But it was only for Kava Scheme
<teddd>dsmith: my understanding is that 1. you write a template, 2. it gets read by the templating program 3. it spits out a file. Like if I give you "echo [1 + 3]" a simple program could return "echo 4"
<teddd>dsmith: yes brl looks like the kind stuff I would need !
<dsmith> https://brl.sourceforge.net/
<teddd>but I would need this in guile
<dthompson>if you need something like jinja2 I guess I don't see much point in using guile
<teddd>my project is in guile so it would be anoying to add a python dependency
<dthompson>oh okay
<dsmith>A long long time ago I kinda ported brl to guile. But I used #> and #< instead of ] and [ That was like guile 1.4 or 1.6 I think.
<dthompson>the scheme way is to use quasiquote. it is the universal templating language. this would require serializers for each format you need to emit
<dthompson>I don't know of any pre-existing unstructured templating system for guile but maybe there is one
<dsmith>#> becuse I could use read-hash-extend
<dthompson>unstructured templating is heavily discouraged in scheme land
<teddd>I'll probably resort to wildly waving rexeps around in a first place and start a templating system from there
<dthompson>I reference this blog post a lot https://www.more-magic.net/posts/structurally-fixing-injection-bugs.html
<teddd>dsmith: interesting. Maybe I'll start with that
<dthompson>about why unstructured templating is an open invitation for injection attacks and other bugs
<teddd>I think I really just need to drop variable values in the files. I don't intend to make them able to request a computation. Does that make it safer ? What could go wrong when just looking up for a variable name ?
<dthompson>injection bugs are probably not a concern for you here, but I just wanted to point out the general problem with string-based templating. because the templating system has no idea about the structure of the thing it is building, it's easy to screw up the output.
<dthompson>and it explains the general lack of a jinja2 equivalent
<dthompson>(though maybe I'm wrong and there is something! I certainly haven't gone looking for it)
<teddd>I see. So you say jinja2 is vulnerable ? What could go wrong for example ?
<dthompson>with jinja2, or any similar templating language, you have to make sure you are escaping input for every single substitution
<dthompson>every time you don't, there's room for bugs
<dthompson>it could lead to something as serious as an injection attack in the case of a web app, but it more commonly leads to annoying things like not escaping double quotes and generating an invalid file or something
<teddd>I see so the problem is when you mix user input and templating at the same time. But say you want to geerate a static site and use jinja2 for generating it, then there is no problem, right ?
<dthompson>if all you need are some regexp replacements, go for it. not trying to discourage. just trying to explain "the scheme way" if you will
<dthompson>teddd: right there's no security issue if it's all your own trusted input.
<dsmith>teddd, Well, it seems the code is lost forever. Was a long time ago, and the code that is in SVN (yes. pre-dates git) doesn't include any .scm files.
<dthompson>but I personally would not want to use jinja2 to generate a static site :)
<Arsen>why not
<dthompson>not when I have quasiquote and sxml
<teddd>dsmith: :( I'll start from scratch and maybe use the syntax then ;)
<dthompson>which is how I generate my own site
<teddd>Oh yes I also would prefer using scheme for a website
<dthompson>anyway I'm starting to feel like I'm talking too much. I don't want to discourage a quick hack that gets things done for you. we all need those ;)
<dsmith>I would think sxml would be prefereable.
<teddd>just cited this example because its probably how most of websites are built juging by the popularity of Django
<dthompson>do what feels right for you. no one knows your needs better than you do.
<dthompson>I've done plenty of erb and handlebars templating at past jobs
<teddd>dthompson: sure thing :)
<teddd>good night !
<dthompson>happy hacking teddd
<teddd>thanks dthompson :D
<dsmith>Wow. I did that gbrl thing 22 years ago!
<dthompson>time...
<Arsen> 22:57:35 <dthompson> not when I have quasiquote and sxml
<Arsen>ah, then fair enough :)
<rebiw>How can I get the text from an error port in guile?. I'm not sure how to use the current-error-port to get the output.
<sneek>wb tohoyn
<tohoyn>sneek: botsnack
<sneek>:)
<apteryx>how do I alias a syntax transformer to something else?
<apteryx>e.g. I have (define-syntax pkgconf-as-pkg-config (identifier-syntax ...)) that I want to export as pkg-config
<dthompson>apteryx: #:export ((pkgconf-as-pkg-config . pkgconfig) ...) in your define-module form I think
<dthompson>pkg-config*
<apteryx>thanks
<dthompson>going from memory, syntax might be slightly different
<dthompson>I don't often export with different names
<apteryx>seems to not work from geiser
<apteryx>error: pkg-config: unbound variable
<dthompson>the manual says this is the syntax for exporting with a different name
<dthompson>probably you have something else wrong
<apteryx>can I export both the original symbol as well as its renamed variant?
<apteryx>here's what it looks like: https://paste.debian.net/1306019/
<dthompson>apteryx: why would you want to export it twice?
<dthompson>I mean I don't see why you couldn't
<apteryx>the rewrite is a hack to keep pkg-config in the code base but point to pkgconf
<apteryx>it still makes sense to have a handle on pkgconf-as-pkg-config at the REPL
<apteryx>to build/inspect it
<dthompson>makes sense
<apteryx>other things I have tried that also didn't work: (define-public new-name old-name)
<apteryx>where old-name is a syntax transformer
<lloda>if you only use the old binding internally you can either use @@ or do a wrapper module for the new binding
<apteryx>actually it seems to work at the REPL using (define-public new old)