Hacker News new | ask | show | jobs
by tedivm 1034 days ago
Does anyone actually use Scheme for real projects? The only places I've ever seen it used have been in classrooms.
16 comments

It's currently used as a back-end for the Idris language. (Which is primarily a research language, admittedly.) It's a fairly popular target for languages to compile to, for similar reasons that C is -- small, well-defined, minimal, many implementations, runs just about everywhere. Very nice compilation target for functional languages in particular, as call/cc can, with reasonable efficiency, implement just about any kind of control flow/evaluation/threading model that you can think of.

Also, used as a scripting language in the GIMP.

The Unison language JIT is being written in Scheme: https://www.unison-lang.org/whats-new/jit-announce/
C is neither minimal nor well-defined, as has been discussed extensively. Random blog post illustrating only some of the issues is here [1]. Just google “undefined behavior c” for a lot more. There are also a bunch of famous rants by Linus Torvalds on his topic.

[1] https://blog.regehr.org/archives/213

can we all agree that the undefined behavior is pretty well identified and documented? Plus, if you understand the entire language and then limit your imagination, C can be quite simple!
It's so simple to avoid undefined behavior, just never add two numbers, or dereference a pointer that you can't statically guarantee the value of.
You can add two numbers. If the operands are signed you just need to check the operands before the addition to make sure you won't cause an overflow.
Which of course cannot be done portably except by drastic restrictions like "never add a number greater than MAXINT / 2 and never multiply a number greater than sqrt(MAXINT)".
Yes, it's a simple language. That's why there are no safe guards around INT_MAX + 1, or variants of that.
I don't think the intention of Idris is to be a research language.
> Idris is primarily a research project, led by Edwin Brady at the University of St Andrews, and has benefited from SICSA (https://www.sicsa.ac.uk) and EPSRC (https://www.epsrc.ac.uk/) funding. This does influence some design choices and implementation priorities, and means that some things are not as polished as we’d like. Nevertheless, we are still trying to make it as widely usable as we can!

-- https://idris2.readthedocs.io/en/latest/faq/faq.html

At this point, the creator has described it as "Pac-Man complete", able and easy to implement a game like Pac Man. (Or itself - it compiles to Scheme but is written in itself.)

Dependent types are still rather new; I believe Idris and its libraries are one of the largest, if not the largest, body of general-purpose software that uses them. (F* maybe?) How to use dependent types properly in a standard library seems be an ongoing development.

The Pac-Man Complete bit is tongue-in-cheek. It's an observation that TC is rarely (if ever) actually needed in practice.

(This might sound strange to people unfamiliar with dependently typed langs, but infinite streams etc., servers that "loop forever" doing request-repsonse can still be modeled without TC.)

What is “TC”?
Thanks for the correction. I misremembered reading something by Brady.
It's intended to be a practical research language. Its niche is as a dependently typed language that is useful for writing real programs. But it also needs to be a toolkit for research into dependently typed programming, since most of the devs have to publish.
Yes, the very website[1] on which you posted this comment is written in Scheme[2], for example.

[1] https://en.wikipedia.org/wiki/Hacker_News

[2] https://en.wikipedia.org/wiki/Arc_(programming_language)

Both of the links you share contradict your statement. ARC isn't scheme, and the hacker news link you posted as a source doesn't mention scheme either.
It's a dialect on top of mzscheme iirc. You're right it's not in scheme per se but used as "runtime target".
I use Racket (a Scheme) for option trading.

https://github.com/evdubs/renegade-way

I've used Scheme a bunch in the past.

These days, I've been using PowerShell for economy data and some options stuff:

https://github.com/dharmatech/options-chain-marketdata.ps1

https://github.com/dharmatech?tab=repositories

Fascinating!

If you hadn't gone with Scheme, what's another language you'd have considered for this project?

Java and JavaFX.
How was your experience with Racket in this case vs Java (assuming you've had some FX experience to contrast it to)?
With Racket:

* I really enjoy using numeric towers and it is upsetting to me every time I go to another language where I can't just work with rationals as a default.

* Having statistics functions, a GUI library, and a plot library all part of the standard distribution is wonderful. Dependencies are kept to a minimum, which I appreciate. Everything feels coherent and not over-engineered.

* Poking around in the large standard library was straight forward and not difficult. I added candlesticks [1] to the plot library without understanding much of the plot library's design or implementation details. I think this would have been much more involved in many other languages.

Where I perceive Java as nicer than Racket:

* I wish Racket had real threads like Java. Having futures and places for actual concurrency / parallelism is not as nice.

* I wish Racket had the rich data structures built in as Java has. You need to reach for an external library for a sorted data structure; this is not ideal.

* Java's performance is great and its future is promising. Java already has some great GCs including low pause time GCs, Project Valhalla will add value objects to Java, and Project Loom will enhance the concurrency functionality offered in Java.

I don't have much JavaFX experience, but my perception is that it would be fine and just as "cumbersome" as Racket's GUI and plot libraries.

[1] https://docs.racket-lang.org/plot/renderer2d.html?q=candlest...

Great example, very readable and with a GUI as well!
Racket is very used in the PLT community (programming language theory) for prototyping programming languages. Lots of cool stuff in this area.

For example, the MIR formality [0] project of the Rust programming language to formalize MIR (their intermediate language) was first prototyped in Racket [1], then rewritten in Rust. [1]'s readme give a rationale:

> For the time being, the model is implemented in PLT Redex. PLT Redex was chosen because it is ridiculously accessible and fun to use. It lets you write down type system rules and operational semantics and then execute them, using a notation that is very similar to what is commonly used in published papers. You can also write collections of unit tests and fuzz your model by generating test programs automatically.

> The hope is that PLT Redex will prove to be a sufficiently accessible tool that many Rust contributors will be able to understand, play with, and extend the model.

> One downside of PLT Redex is that it doesn't scale naturally to performing proofs. We may choose to port the model to another system at some point, or maintain multiple variants.

[0] https://github.com/rust-lang/a-mir-formality

[1] https://github.com/rust-lang/a-mir-formality/tree/1f40120f09...

Guile Scheme is used extensively in the Guix linux distribution, and works quite nicely there.
extreme niche on extreme niche.
Guix is niche, but it's very much 'real software'. It does useful things well, and it solves some problems that very few competitors adequately do. It's used for reproducible scientific computing on some HPC clusters, which is a pretty cool niche if you ask me.

The Guix package collection is also sizeable and growing exponentially-- within a few years, it'll probably outgrow most Linux distros in terms of size.

Which is terribly unfortunate, because it solves very non-niche packaging problems in a very elegant way.
I had to use Nix in a project of mine and was surprised at how clunky it felt compared to guix. Writing packages meant string concatenations and juggling outputs to the command line.

I prefer guix. Every day of the week.

Same here. I used NixOS as my desktop operating system for a few months I think. It did not go great. After hopping a to a few other distros, now I've been using Guix as my OS for a few years.
Unless they have quietly rewritten it, HN itself is written in Scheme. Or, more precisely, it is written in Arc, which is implemented in Scheme.
For "precisely" read "correctly". Unless the implementation language is exposed to users of the implemented language, it doesn't matter what the implementation language is. gfortran is written in C and C++, but that does not mean Fortran programs are written in C or C++.
Okay, I think what I said was clear enough, but if we're splitting hairs, I'll say: that's a bad comparison because gfortran is compiled to machine code. When you run a gfortran program, you're not executing anything that was written in C.

When you run e.g. Python, the runtime written in C is indeed being executed. If nothing else in the world was written in C except the Python runtime, IMO it would still be fair to say that C is widely used. A security flaw in C compiler could potentially cause a vulnerability in any Python program.

The question was "is Scheme used for anything in production?" and it is correct to say "yes it is used for HN" even if HN is not directly written in Scheme.

I chose Racket for a project that involved lots of AST manipulation. Those ASTs were already in s-expression format, so Scheme seemed a natural fit.

The lack of static types was annoying; Typed Racket helped, but was so slow I only enabled it during unit tests (more precisely: Typed Racket functions can be faster than those written in normal Racket, but calling them from normal Racket functions will be slow as it performs run-time checks)

https://github.com/Warbo/theory-exploration-benchmarks/tree/...

Around 20 years ago I worked on commercial email filtering/archiving system implemented in MzScheme (now PLT) - it was relatively small code base, but very powerful.

I wrote an article about it in Russian (almost 15 years ago), for some reason google translate doesn’t work for archive url: https://web.archive.org/web/20210506123442/http://fprog.ru/2...

Naughty Dog used Racket as part of the development of The Last of Us.

[0] https://www.youtube.com/watch?v=oSmqbnhHp1c

Chicken Scheme is a high performance source-to-source (C) Scheme that supports the R5RS and R7RS (work in progress) http://www.call-cc.org/
I assume that Cisco is using Chez Scheme for something since they bought it (and open sourced it).
We use Gerbil/Gambit scheme in production. The new actor system makes it a very compelling.
How do you handle Gerbil's incomplete docs? I'll admit, when I was looking at them I had no clue how Schemes worked, but I found the lack of documentation to be a very difficult barrier.
i would wager that anyone ballsy enough to use gerbil in production is at a minimum very active on gitter and probably a contributor to the language
Remember Gerbil is a layer on top of Gambit, which has been 30 years in the making.
Gitter has been a great resource. Vyzo is very helpful in answering questions. The docs could use some work. But the code is fairly trivial to follow on most things.
I used it just the other day to work an aime problem for my middle schooler.

scheme@(guile-user) [5]> (exp (* (atan 1) -2))

$9 = 0.20787957635076193

scheme@(guile-user) [5]> (expt 0+1i 0+1i)

$10 = 0.20787957635076193+0.0i

a problem c/c++/java/js/python/rust/go can't handle after decades of progress. even my favorite R can't work this problem. scheme ftw.

Hmm. Python 3.11 (didn't test in earlier)

>>> from math import atan, exp

>>> exp(atan(1)*-2)

0.20787957635076193

>>> 1j**1j

(0.20787957635076193+0j)

thank you. i tested this on lc playground and yeah it does work.
I think this is probably because you did not know how to type a complex number in R. The coefficient of i is not optional.

    > exp(-2 * atan(1))
    [1] 0.2078796
    > 1i ** 1i
    [1] 0.2078796+0i
As well as python noted in a sibling, Ruby handles this quite well out-of-the box.

Is your complaint just that some popular languages don’t have complex numbers as part of the core/stdlib?

The issue is that lots of languages don't make complex numbers part of what Lispers call the numeric tower, fully integrated into numeric operations, even if there is a complex library. Here's Guy Steele's 3-part smoke test for early Common Lisp implementations:

1. At the REPL, if you type `T` (true), and you get back `T`, the test passes.

2. Define factorial. Then type `(/ (factorial 100) (factorial 99))`. If you get back 100, the test passes.

3. Type `(atanh -2)`. If you get a complex number, the test passes. If you get the correct complex number [namely -0.5493061443340549+1.5707963267948966i] extra credit. Far too many non-Lisp languages return NaN or throw an exception.

What's the "aime problem" and why can't c/c++/java/js/python/rust/go handle it?
I did a little googol and found out it's like an accelerated math thing https://artofproblemsolving.com/wiki/index.php/American_Invi...
Okay, I was just wondering if there's something non-obvious here. I guess OP is just woefully misguided about languages other than scheme or "these languages can't handle it" means something more like "I don't know how to use those languages".
Decent complex types and library calls to do exponentiation, etc, don't always come for free in any given language environment. It's nice that it "just works" in many scheme environments (but this is not the only language runtime where this is true and it's not something that you can't work around).
The example the OP cited doesn't involve complex numbers. Atan(1) is pi/4.
To be clear, it's a competitive exam and one of the primary feeders into the USA Math Olympiad team.

Many problems are quite challenging.

yeah it looks like everybody's focused on the mechanics of the computation and not appreciating the math i.e. why the two expressions compute to the same value.
We are not in an algebra II class. We are talking about the merits of scheme. You posted a relatively opaque comment and made a relatively unfounded assertion about whether other languages could do it.

It might have been better for you to have been a little more direct-- "I like that exponentiation of complex types just works in Scheme; I don't think that works in other languages!"

I'm not sure why you think scheme is unique in being able to do this-- indeed, it's one of the examples of std::pow on cppreference:

https://en.cppreference.com/w/cpp/numeric/complex/pow

> std::cout << "i^i = " << std::pow(i, i) << '\n';

> i^i = (0.207880,0.000000)

I also hope it wasn't a way to humblebrag that you have a kid in middle school that knows math that lots of other people around here don't (having forgotten it from alg2/precalc or just having trouble reading your comment). Know your audience and prevailing context, and be clear.

I think the biggest issue with any lisp is that it's just too damn powerful of a language. This makes it super easy for developers to create their own little ecosystem of macros and functions that nobody else can understand. This can be absolutely disastrous for large teams and companies looking to hire.

Languages that force you to be more verbose and don't let you build your own ultra-powerful abstractions seem to work better for large teams where you can force everyone to adopt a standard style. This makes onboarding much easier too.

I dunno, I got a (Common) Lisp job, and I don't think I've ever had a problem where I didn't understand the semantics of a macro; people aren't just making a ton of them all the time for no reason, and the ones that are popular are from popular libraries (e.g. alexandria and iterate) and have clear semantics.

I think the same problem applies perfectly well to developers who "create their own little ecosystem of classes and functions nobody else can understand" -- I don't think [0] would be made any harder to understand by having macros involved.

[0]: https://old.reddit.com/r/programming/comments/15s0lp6/how_we... (only picking on it because I saw it recently)

People say this, but it hasn't been my experience in practice—the worst, most complex codebases I've seen have been in Python and Java.

But I guess they look simple and uniform at a superficial, syntactic level. If you can't follow that it's your fault, if you can't follow Lisp code it's Lisp's fault...

Isn't Julia's parser still in Scheme?
For now, yes. The upcoming 1.10 release (which is now in beta) will switch to a pure Julia parser as the default (with the old Scheme parser available as an option).

Not because of any fault with Scheme per se (afaik), just that contributors to Julia are more likely to know Julia than Scheme, so it makes sense from a maintanence point of view.

note that in 1.10 scheme is still used for lowering (simplifying AST to IR which is a lot of code for julia)
Femptolisp, a "Scheme dialect"
Like all lisps it is niche. I don’t use scheme but have used Common Lisp and clojure for a few years. Racket has a thriving community as far as I can tell. You just don’t see lisp much in the wild but it’s there.
My totally uneducated and uninhibitedly snarky guess is that people who use any Lisp family language (except maybe Clojure) don't go around talking much about that fact, or thumping their chests about it, unlike (some) Ruby, Python or JS users. They probably just quietly go about using it and having fun, and talk about it when they meet each other.