Live data from Hacker News

Optimizing Guile Scheme

dthompson.us

41–50 of 82 posts

Re: Optimizing Guile Scheme

#41
post #8

These sorts of optimizations can and should be handled by a (sufficiently smart (tm)) compiler. Common Lisp/SBCL is usually sufficiently smart. I know not everyone likes Common Lisp, but at least I would have tested it with something more performant that Guile, like Chicken Scheme (my favorite!), Chez Scheme, etc. I like Guile and its purpose as a universal scripting language. However, its performance issues are well…

Part of the problem is that raw Scheme is spectacularly underspecified. It also doesn't help that Schemes like Guile are also interactive. The domain of an interactive language and a "compiled" language are quite different. Given the entirety of the program made available to the compiler all at once, there are high level derivations that can happen notably through flow analysis to let the compiler make better decisio…

> Given the entirety of the program made available to the compiler all at once, there are high level derivations that can happen notably through flow analysis to let the compiler make better decisions. But do that in an interactive environment when the rug can be pulled out of any of the assumption the compiler made, and things get messy quite quickly.

Haskell's GHC does quite well with its 'ghci' interactive environment. GHC is a compiler first and foremost, and as far as I can tell, ghci works by compiling each line you give it one by one? (But even in ghci, you have to abide by the type system of Haskell, so that might help.)

The Common Lisps were always pretty good at combining compiled and interpreted parts, even in the same program. And I think OCaml also does a good job of combining the two approaches?

Re: Optimizing Guile Scheme

#42

I have such mixed feelings about dynamically typed languages. I've designed a whole pile of hobby programming languages, and dynamically typed languages are at least an order of magnitude simpler to design and for users to learn and start using. At the same time, they inevitably seem to lead to user stories like this where a user really does know exactly what types they're working with and wants the language to know…

As a long-time Python and JavaScript user, I've come to the conclusion that dynamic typing is just not a good idea for anything beyond exploratory or very small projects.

The problem is that you invariably have to think about types. If you mistakenly pass a string to a function expecting an integer, you better hope that that is properly handled, otherwise you risk having type errors at runtime, or worse—no errors, and silent data corruption. That function also needs to be very explicit about this, but often the only way to do that is via documentation, which is often not good enough, or flat out wrong. All of this amounts to a lot of risk and operational burden.

Python's answer has historically been duck typing, which doesn't guarantee correctness so it's not a solution, and is more recently addressing it with gradual typing, which has its own issues and limitations. Primarily that if specifying types is optional, most programmers will not bother, or will just default to `any` to silence the type checker. While for JS we had to invent entirely new languages that compile to it, and we've reached the point where nobody sane would be caught working with plain JS in 2024.

Static typing, in turn, gives you a compile time safety net. It avoids a whole host of runtime issues, reduces the amount of exhaustive and mechanical tests you need to write, while also serving as explicit documentation. Code is easier to reason about and maintain, especially on large projects. You do lose some of the expressiveness and succinctness of dynamic typing, but what you gain with static typing is far more helpful than these minor benefits.

Re: Optimizing Guile Scheme

#43
post #19
post #8

These sorts of optimizations can and should be handled by a (sufficiently smart (tm)) compiler. Common Lisp/SBCL is usually sufficiently smart. I know not everyone likes Common Lisp, but at least I would have tested it with something more performant that Guile, like Chicken Scheme (my favorite!), Chez Scheme, etc. I like Guile and its purpose as a universal scripting language. However, its performance issues are well…

I switched from Guile to SBCL because I really like having things such as (declare (inline my-function)) and (declare (type Double-Float x y z)). Now if only it had case-lambda, named let, and a better deftype which can specify members of classes and/or structs.

The language-hack of the "the" operator in Common Lisp, whereby `(the fixnum (+ 5 7))` signals that the result of (+ 5 7) should be an integer is so ... lispy.

Re: Optimizing Guile Scheme

#44

I have such mixed feelings about dynamically typed languages. I've designed a whole pile of hobby programming languages, and dynamically typed languages are at least an order of magnitude simpler to design and for users to learn and start using. At the same time, they inevitably seem to lead to user stories like this where a user really does know exactly what types they're working with and wants the language to know…

I think Common Lisp got it exactly right. Strongly typed dynamic language where you can optionally specify types for the extra performance/correctness if need be (especially with SBCL). Honestly, I think weak typing is more of an issue than dynamic typing and people cry for static types when they suffer mostly from the former. Dynamic typing is great because it allows you to have extremely complex types for basically…

I find much the same to be true. I'm a big fan of Racket's define/contract and clojure's Malli/guardrails. You get one of the biggest benefits of static types (code that self-documents the expected shape of data) while enjoying all the benefits of a dynamic language (like creating types at runtime, and repl-driven development).

Re: Optimizing Guile Scheme

#45

I have such mixed feelings about dynamically typed languages. I've designed a whole pile of hobby programming languages, and dynamically typed languages are at least an order of magnitude simpler to design and for users to learn and start using. At the same time, they inevitably seem to lead to user stories like this where a user really does know exactly what types they're working with and wants the language to know…

I think Common Lisp got it exactly right. Strongly typed dynamic language where you can optionally specify types for the extra performance/correctness if need be (especially with SBCL). Honestly, I think weak typing is more of an issue than dynamic typing and people cry for static types when they suffer mostly from the former. Dynamic typing is great because it allows you to have extremely complex types for basically…

I wish Common Lisp had integrated type declarations with TYPEP and CHECK-TYPE, instead of punting with "consequences are undefined if the value of the declared variable is not of the declared type," i.e., sucks to be you.

Re: Optimizing Guile Scheme

#46
post #38

Earlier quoted context omitted.

I haven't done FFI with Racket, but https://docs.racket-lang.org/foreign/index.html looks reasonably approachable?

That seems to let you call C functions from Racket, but I don't see how it lets you embed Racket in a C program and call Racket functions from C. So it's at best half a solution, unless I'm missing something.

See https://docs.racket-lang.org/inside/cs-procs.html

Re: Optimizing Guile Scheme

#47

Earlier quoted context omitted.

I think Common Lisp got it exactly right. Strongly typed dynamic language where you can optionally specify types for the extra performance/correctness if need be (especially with SBCL). Honestly, I think weak typing is more of an issue than dynamic typing and people cry for static types when they suffer mostly from the former. Dynamic typing is great because it allows you to have extremely complex types for basically…

I wish Common Lisp had integrated type declarations with TYPEP and CHECK-TYPE, instead of punting with "consequences are undefined if the value of the declared variable is not of the declared type," i.e., sucks to be you.

No doubt you know this, but Common Lisp's standardization gave leeway to implementations. So you could choose which implementation suits you better. Common Lisp is an umbrella for different Lisps to have some commonality. It was a process of negotiation, during a time when there were many design forks in the road, and diverse use-cases

For example, type declarations can enable performance optimizations, compiletime type checking, runtime type checking, IDE autocompletion, etc. Or they can be ignored, if compiler simplicity is more valued. All these things have engineering tradeoffs. For example, runtime checks may have runtime costs at odds with performance optimization

There might be higher-value improvements to Common Lisp, if higher quality code is desired

Re: Optimizing Guile Scheme

#48
post #42

I have such mixed feelings about dynamically typed languages. I've designed a whole pile of hobby programming languages, and dynamically typed languages are at least an order of magnitude simpler to design and for users to learn and start using. At the same time, they inevitably seem to lead to user stories like this where a user really does know exactly what types they're working with and wants the language to know…

As a long-time Python and JavaScript user, I've come to the conclusion that dynamic typing is just not a good idea for anything beyond exploratory or very small projects. The problem is that you invariably have to think about types. If you mistakenly pass a string to a function expecting an integer, you better hope that that is properly handled, otherwise you risk having type errors at runtime, or worse—no errors, an…

Dynamic typing with deeply nested data forces you to put type bandaids all over the code. For example you end up defining Pydantic schemas and then validating the same thing more than once since you can't guarantee that the type of a thing was not changed somewhere in the middle.

Dynamic typing forces you to test behavior which could be tested much more thoroughly by a type checker, at compile time, with zero development time.

Dynamic typing does offer much faster time to early prototyping but then drags you down with each bug.

Static typing does force some early commitments to the structure of the data but it also allows faster iteration and refactoring.

Static typing with good type inference seems the best to me.

Re: Optimizing Guile Scheme

#49
post #8

These sorts of optimizations can and should be handled by a (sufficiently smart (tm)) compiler. Common Lisp/SBCL is usually sufficiently smart. I know not everyone likes Common Lisp, but at least I would have tested it with something more performant that Guile, like Chicken Scheme (my favorite!), Chez Scheme, etc. I like Guile and its purpose as a universal scripting language. However, its performance issues are well…

In my experience, guile these days is often faster than chicken, even compiled (the csi interpreter is dog slow and not suitable for anything but interactive exploration). Chicken is just not a fast implementation.

Plus guile comes with a more comprehensive standard library; on the other hand, chicken's package manager and available packages do make up for that.

Re: Optimizing Guile Scheme

#50
post #29
post #12

Earlier quoted context omitted.

Isn't Racket the 'default' Scheme? (Even though it's no longer called Scheme.)

I don't think there's a real 'default' Scheme, like Chez is probably the implementation which generates the fastest code, but if I'm not mistaken it only implements the R6RS spec, Guile is quite performant and supports both R6RS and R7RS Small, Chicken has a bunch of libraries (the 'eggs'), but I think it's R5RS (I may be wrong), and of course GNU/MIT Scheme is what you want to follow along with MIT publications work…

For SICP, the best option is probably Racket with the sicp language package.

I can't recommend MIT Scheme for anything these days; it's just missing too many things that I feel are required for real work in Scheme, and has too many idiosyncrasies and quirks. Even using it to run a standalone program written in Scheme is a pain.

Post reply on HN