Hacker News new | past | comments | ask | show | jobs | submit login
Racket is 25 (racket-lang.org)
358 points by azhenley 11 months ago | hide | past | favorite | 161 comments

Taking an SICP-like class in Racket and playing with recursive constructs for the first time was one of the highlights of my CS education. This language gave more unalloyed joy than anything else I've done as a programmer, though I've yet to build anything practically useful in it.

I thought similarly too, until I spent some time with Prolog. Lisp seems wonderful and clever, but Prolog feels even more magical.

Even a simple thing like concatenation of two lists, that in Prolog it could be done purely declaratively, without expressing how it needs to be performed, seems levels more magical than how it is done in lisps.

> Even a simple thing like concatenation of two lists, that in Prolog it could be done purely declaratively, without expressing how it needs to be performed, seems levels more magical than how it is done in lisps.

Not to argue with the claim—Prolog does feel magic sometimes—and maybe I'm not sufficiently idiomatic in Prolog, but I would express them similarly: something like

    concat([], Bs, Bs).
    concat([A|As], Bs, [A|Cs]) :- concat(As, Bs, Cs).
I don't have Lisp code at my fingertips, but that's quite like how I'd do it in Haskell:

    concat [] bs = bs
    concat (a:as) bs = a:(concat as bs)
(I just looked up a Scheme primer to refresh myself, and I think there I'd do

    (define (concat as bs)
        (if (null? as)
            (cons (car as) (concat (cdr as) bs))))
… but don't hold me to it. Certainly not using pattern matching makes the Scheme more verbose, but I think the algorithms are the same.)

Is one of these an un-idiomatic way to do it? (If you downvote, of course that's your right, but I'm not being sarcastic or dismissive; I really would like to know, as not a professional programmer in or fluent speaker of any of these languages, if I'm not writing idiomatically, so I'd be grateful if the downvote came with a comment!)

As far as I (not a Prolog expert) know, your Prolog is idiomatic. But it is more declarative than your Haskell or Scheme implementations: you didn't just define a concat function, but a concat relation, which means you can use it in many more ways. Here are just a few examples from the top of my head.

- The head function (with X unknown and L known): concat([X],_,L).

- Produce all splits of a list (with X and Y unknown): concat(X,Y,L).

- Does this list start with the prefix [a,b]? If yes, let Y be the tail (Y unknown): concat([a,b],Y,L).

... and many more.

This is one of the most magical things about Prolog.

From my functional/imperative programming experience, when originally picking up Prolog, I conceptualized the kind of operations you describe (e.g., “all splits”) as “running the function backwards” — going from output L to inputs X, Y.

But as you write, the truth is that Prolog is modeling the relation of concatenation.

What is magical apart from pattern matching is how you can invocate it with mixed ground terms and variables, and it computes values that makes the relationship holds. For example:

    [eclipse 2]: concat(A,[_,_],[0,1,2,3,4]).

    A = [0, 1, 2]
    Yes (0.00s cpu, solution 1, maybe more) ? ;

    No (0.00s cpu)
Or iterate over all lists that concatenate as [0,1,2]

    [eclipse 3]: concat(A,B,[0,1,2]).
    A = []
    B = [0, 1, 2]
    Yes (0.00s cpu, solution 1, maybe more) ? ;
    A = [0]
    B = [1, 2]
    Yes (0.00s cpu, solution 2, maybe more) ? ;
    A = [0, 1]
    B = [2]
    Yes (0.00s cpu, solution 3, maybe more) ? ;
    A = [0, 1, 2]
    B = []
    Yes (0.00s cpu, solution 4)

FWIW there is of course pattern matching in Racket. The program is practically identical to the Haskell version.

    (define (concast as bs)
        (match as
           ['()         bs]
           [(cons a as) (cons a (concat as bs))]))

> Is one of these an un-idiomatic way to do it?

I think the Scheme version might be considered unidiomatic due to the inefficiency: because it's not tail recursive, you're building a huge stack of cons calls (whose depth is the length of `as`) which only resolve once you reach the end of `as`.

On the other hand, the version with accumulator would need to traverse as and bs in full, twice (once for the accumulation and once for the terminal reverse).

There is a difference between Racket and Scheme. In Racket you will never get a stack overflow. You can of course exhaust memory, if you allocate too much, but the stack is guaranteed not to overflow.

    > At the same time, recursion does not lead to particularly 
    > bad performance in Racket, and there is no such thing as 
    > stack overflow; you can run out of memory if a computation 
    > involves too much context, but exhausting memory typically 
    > requires orders of magnitude deeper recursion than would 
    > trigger a stack overflow in other languages. These 
    > considerations, combined with the fact that tail-recursive 
    > programs automatically run the same as a loop, lead Racket 
    > programmers to embrace recursive forms rather than avoid
    > them.

> There is a difference between Racket and Scheme

AFAIK the Scheme standard doesn't specify either behaviour. So, with regards to the standard both Racket and other Scheme implementations are free to implement this in whichever way they prefer. And the Scheme implementations that I'm using (Gambit-C, Chicken and Guile) all work the same as Racket. I only know of Bigloo (of about 10 years ago, maybe it changed?) as a Scheme implementation that uses the machine stack to implement Scheme continuation frames, and Bigloo (again back then) doesn't (didn't?) implement call/cc efficiently either. Arguably to implement the Scheme standard including call/cc efficiently the machine stack can't be used, thus any 'proper' Scheme implementation will behave like Racket.

I've written lots of non-Racket Scheme code and my code always assumes that it won't run out of stack before running out of heap. Some Scheme implementations allocate stack frames more efficiently than cons cells thus the straight-forward solution (recursion, not iteration then reversion) is also the more efficient one.

There is a tendency of claiming Racket is somehow fundamentally different from Scheme which sometimes feels a bit like a racket. I'm not opposed to Racket but think it would be better to take it as what it is, Scheme plus extensions and tooling, which most other Scheme implementations are as well. Racket may be doing that more extensively but I think it calling itself a different language should primarily be understood as a marketing ploy, or maybe as a move to justify moving ahead with own ideas without caring about the rest of the Scheme community.

I agree that some Scheme implementations have the same guarantee - it's not in the Scheme standard though (as far as I know), which makes it difficult to rely on, if you are programming to the spec.

It is difficult to use the machine stack and have a fast call/cc. But I think Chez Scheme proves it's possible.

> it's not in the Scheme standard though (as far as I know), which makes it difficult to rely on, if you are programming to the spec.

If you want to have code work everywhere and thus code defensively, yes. Of course you're not coding defensively when coding for Racket, either. But I guess I may have misunderstood you--Racket simply gives you a guarantee; as do some (other) Scheme implementations, so you get the same benefit with some/many other Scheme implementations as well--but even those "differ from Scheme (the standard)", by giving such a guarantee outside of the standard. It's not "Racket vs. Scheme implementations", it's "the (Racket|Scheme) implementations vs. Scheme (the standard)". Apologies then for my inappropriate rant about false claims.

> It is difficult to use the machine stack and have a fast call/cc. But I think Chez Scheme proves it's possible.

Chez doesn't seem to be using the machine stack either. I've tested with this code and "ulimit -s 1000" on Linux and it runs fine:

    (define (conc a b)
      (if (null? a)
          (cons (car a)
                (conc (cdr a) b))))

    (define (iot n)
      (if (negative? n)
          (cons n (iot (- n 1)))))

    (display (length (conc (iot 10000000) (iot 10000000))))
Note that it can still be using a stack built from "machine" or C style arrays as building blocks--that's what I meant with "Some Scheme implementations allocate stack frames more efficiently than cons cells". Gambit falls into this category as well. But you can't have a single uninterrupted C style array as the stack (with no copying during GC like Chicken does) and implement call/cc efficiently. So I'd still say that implementing Scheme including call/cc efficiently means moving away from the stack controlled by ulimit -s, and once that is done it's easy/natural for an implementation to also offer unbounded stacks like Racket does.

I think we agree: an implementation that uses a stack to make normal calls fast, needs to move/copy the stack to the heap, when the stack runs out (or when a continuation is captured).

I don't know whether Chez still uses the same strategy, but a major part of Dybvig's thesis (very readable) was dedicated to explain the details of a possible implementation strategy.


Actually pattern matching is easy to implement in fact its implementation is given in SICP Section 4A Pattern Matching and Rule Based Substitution. And most modern lisps have it.

Looks right to me except the Scheme version is not tail-recursive, so there's a possibility of stack overflow.

The good thing is you can have both: https://mitpress.mit.edu/books/reasoned-schemer

Something I would like to see is Prolog/logic programming embedded in a general purpose programming language, rather than as a standalone system.

Racket and Perl 6 are the only small userbase languages in the last 8-10 years to amaze me with their feature sets and to make me want to learn them just for the sake of experiencing them.

Probably doesn’t fit what you mean by mainstream, but even so: https://github.com/clojure/core.logic

> A logic programming library for Clojure & ClojureScript. core.logic offers Prolog-like relational programming, constraint logic programming, and nominal logic programming for Clojure.

This is cool but less what I'm looking for, which is to actually write Prolog inside my Clojure source, or be able to include a Prolog file.

Minikanren seems to be closer to the mark, and I thank the commenters who pointed it out!

I think you oversaw that core.logic is basically a minikanren (plus c-kanren, plus alpha-kanren) implementation in clojure instead of scheme; it even points to the papers and to The Reasoned Schemer for documentation and reference.

That is, saying that minikanren seems to be closer to the mark than core.logic is a little bit nonsensical (please read that in a good sense!)

You're right, although I think what I was actually wrong about was what minikanren is (probably by looking at examples in languages I was less familiar with).

I don't want to do logic programming in clojure (or whatever other language), I want to do logic programming in Prolog and drop it into my clojure project and have to do as little plumbing as possible.

The nearest analogy I can come up with is LINQ. In the examples in [1] the experience of the developer is closer to writing SQL in the middle of a C# or VB file, rather than having a good C# database query library.

[1] https://docs.microsoft.com/en-us/dotnet/csharp/programming-g...

Please note that Perl 6 has been renamed to Raku (https://raku.org using the #rakulang tag on social media). Although the emphasis has been on stability and efficiency improvements, some advances have been made in the concurrency department (react whenever) since then. And a project is now underway that will result in macros becoming first class citizens in Raku.

There is probably a logic programming system for your favorite language. MiniKanren might not be exactly what you want, but even then there's probably something Prologgy too.

> Something I would like to see is Prolog/logic programming embedded in a general purpose programming language, rather than as a standalone system.

That's super common, both as bridges to Prolog systems from other host languages and as implementations of Prolog semantics (or a subset like Datalog) as libraries in other host languages; also MiniKanren is available for many host languages.

Just to name two less know but interesting languages with that feature:



That's been a regular thing to do for many years. There are systems in Python, many systems for various Lisps, even a few in C++.

Have a look at minikanren : )

Lisp has several. Screamer comes to mind.

One of the coolest libraries I've ever had the pleasure of using is for Racket: Redex (https://redex.racket-lang.org/)

This is really neat. Is any of your code that uses this open source?

Not yet, but here's a great tutorial that introduces a really cool technique called Abstracting Abstract Machines: https://docs.racket-lang.org/tutorial/index.html

I feel the same but unlike you I don’t care much about doing something practical. Well, I do, but am forgiving if the efficiency is not there. Just playing around with bigbang I came up with some game ideas that would not have come in a different environment. My take is that it is an environment fertile with creativity and ideas due to simplicity of scheme. Those can be taken and rebuilt elsewhere if needed. To me the joy is in the playground.

> This language gave more unalloyed joy than anything else I've done as a programmer, though I've yet to build anything practically useful in it.

Ain't that the truth. Scheme/Racket, ML and other primarily academic functional languages are fun, but rarely used in business/industry. It's great for learning programming language ideas like scope, thunks, closures, etc but very little opportunity beyond that. But maybe that's why it was a joy to program with racket. No pressure to create anything practical with it. Just tinker and learn using it.

I've found J joyful!

I still need to pick up SICP again :)

I used Racket a lot about 2 months ago. I was prototyping an application [1] in three different languages: Racket, LispWorks Common Lisp, and Swift.

Racket produces standalone applications that can be codesigned using Apple's tools, in preparation for their App Store.

Best regards to the Racket team.

[1] http://www.knowledgegraphnavigator.com/

I read co-designed instead of code-signed. Took me a bit to make sense of it.

> Racket produces standalone applications that can be codesigned using Apple's tools

Can you elaborate on how this works? I've been wanting to try something similar.

My codesigning notes for Racket

Build an application, unpack the .dmg file, add my own data files, create a new subdirectory with same name and move all files into it, discard the dmg, use Disk Utility to build a new .dmg and sign it:

codesign --force --deep --options runtime -s mark@mydomain.com -v New.dmg

Note: my app had required data files, which complicated the process.

I’ve figured out a somewhat automatic way to do the dmg bundling which may be of interest:


The manifest file used is here:


It’s a bit annoying because it requires having a working node installation, but I found the whole process of building and configuring a dmg much too manual and undocumented to not use some kind of utility for.

Out of the 3, which one did you stick with? Racket?

Could you give a quick overview of the reasoning behind your final decision?

I can't reply for Mark, but the commercial lisps have a development experience that is hard to match. When using CLOS you get an extra smalltalky experience which the other CL implementations lack. And the debuggers are superior in just about every way.

Racket is nice and all that, but the commercial CLs are just that: commercial, aimed at people writing large programs with very high demands.

Anecdote: I once hit a weird bug when trying to get a very old CL program running. Nothing big, but once in a blue moon I would get the wrong result. I spent 3 days banging my head angainst it, trying to find a way to trigger it reliably. I inspected the live environment, did print-debigging. A friend encountered the same bug when running the program in Allegro CL and managed to debug it within minutes.

LispWorks Common Lisp. I have always liked Common Lisp better. LispWorks costs $3400 and Racket is obviously free.

I usually recommend Racket when someone, at least right now, wants to learn Lisp. Racket is an effective gateway drug to the Lisp world :-)

I've always wondered what LispWorks offers that costs so much. Is it the libraries, better IDE, or something else? Looking at Racket's documentation, it seems pretty "complete" with regard to things it covers (for free).

LispWorks and Allegro are the survivors from the Lisp Machine days.

They offer the full development experience as having your own Lisp Machine, with optimizing compilers, IDE, frameworks, debugging tools.

The cross platform CAPI UI library is good, as are the bundled dev tools. The will give you an evaluation license to try it.

I've picked up Racket recently after a long while and I'm enjoying it.

Does anyone have recommendations of how to learn to think recursively? Sure, using the language more and more does it, but what about a more general recursion as a problem solving paradigm pattern? I'm enjoying doing recursive code exercises and got into Backtracking problems. Creating things like Sudoku solvers, Knight's Tour grid etc was quite fun. I still can't develop recurrences easily though.

Any books/exercises that people here found helpful?

This paper, "Programming by Numbers: A Programming Method for Novices", presents a recipe of how to design recursive functions:


And the "The Little Schemer" book has a series of exercises that expose recursive thinking:


Hope this helps!

I would say the vast majority of How to Design Programs (https://htdp.org/) is about exactly this. It's not presented this way, but that's what the Design Recipe makes you really good at.

One way to learn some of using recursion while using Racket (or any other Scheme) is to:

* avoid the iteration constructs that Racket added to Scheme,

* avoid mutating operations, such as `set!` and those that operate on mutable data types,

* embrace named-`let` for iteration/recursion (using `let` with a name, like `(let loop-for-foo (` rather than `(let (`, which effectively makes it like an embedded function that can be called from within its own definition), and

* embrace immutable data for collections, like immutable pairs and immutable hashes.

You can do that for real-world development, or for interview-oriented Leetcode-type exercises. Whichever motivates one more; with the above suggestions, both will present many opportunities to practice recursion this way, without exercises that are selected or contrived to need recursion.

I agree, but regarding the for constructs, I don't think many people know: Racket's for loops are just (mostly) left folds over whatever sequences you use. They become as efficient as hand-rolled named lets.

And then people don't get comfortable with recursion, and when they have an algorithm that doesn't quite fit a `for` exactly, they do things like mutate a flag variable. :)

I think that situation is unfortunate for some aspects of learning, whether or not the compiler can make some use cases of the constract just as fast (or faster).

I agree! I solved it by implementing mostly-racket-compatible for loops for guile scheme. Since then I can't not think of for loops as recursive macros :)

Edit: the loops actually got more powerful recently: The for/foldr was a great addition where you can replace most non-tail-recursive functions with it, even though I probably wouldn't use it for tree transversal :)

if Racket was built on top of immutable data structures, recursion, and the likes - why were imperative-like features such as mutation added to the language?

Scheme was defined as an algorithmic language, not a strictly pure-functional one, though it also included some functional features and permitted other functional abstractions to be implemented.

Racket slowly added some immutable data types to Scheme, which was a nice fit for some other Scheme features that had been there from the start, and better for software engineering (e.g., enforce that a user of a module couldn't go and mutate data you were sharing with them).

As I haven't used Racket for anything professionally, I can't really answer the question with Racket in mind.

But Clojure is also built on top of immutable data structure, recursion and more, but also provides features for mutation of various things, both for pragmatism and sometimes performance. Clojure also lives like a hosted language (on top of JVM/browser engines/more), most of them being mutable by default, so providing those constructs help with interop as well.

As a programmable programming language, I think it would be a shame if someone wants to use mutation and it's not available. On the other hand, if you don't want to use it, then don't use it! If you are a language creator that doesn't want your client to use variable mutation, you can even choose to not provide the construct very easily (see the Beginning Student Language which does exactly this).

It's not so much that mutation was added to racket. Racket started as a scheme, which has mutation. Some of that, like set-car! and set-cdr! were removed (cons cells were made immutable, though mcons was added for mutable cons cells) set! is one wasn't removed. I think removing set! would constitute a much more radical departure from scheme than what's been done already.

as others have said, the little schemer (for functions) and also the little mler (for types) are purpose built to thinking about functions and types recursively.

also, the coursera course programming languages by dan grossman is an excellent course on doing things recursively. in part a, you learn sml, and in part b, you learn racket and build a simple interpreter.



I actually finished that course when it first came out (and was a single course as opposed to a 3 part breakdown) way back, like 4-5 years ago.

Thanks all for the suggestions! :)

I like EOPL 3rd edition, the first two chapters are pretty much dedicated to explaining recursion [1].

1: https://en.wikipedia.org/wiki/Essentials_of_Programming_Lang...

The little schemer is a book purpose built to teach this.

> "If functional programming is that good, why is nobody using it?"

In the past 25 years, I think we've seen quite clearly that programming language popularity depends on many different factors, and "quality of he underlying paradigm" is way down on that list -- if it's even a factor at all.

Just a quick glance at any list of most-used-languages will tell you that 50% of popularity is "is it being pushed by a big company?", and 25% is "is it the primary interface for a popular platform?"

Take away those two factors and there's maybe only about 3 languages left in the top 25 (Python, Ruby, PHP?).

Where quality shines is in being able to stay a viable niche for a long period of time. That's Scheme.

Oh, lots of people are using functional programming. They just don't use the paradigm exclusively nor do they use a purely functional programming language. Let's see,

- Supporting higher order functions in programming languages. Check.

- Usual operations on higher-order functions like currying? Check.

- Functional reactive programming. Check. Rx was a big thing a few years ago.

- Purely functional data structures. Check. Even Java has a few reasonably popular libraries that support such data structures.

- Using referential transparency whenever we can. Check.

- Using CPS (continuation-passing style) in daily programming. Check.

- Using recursion in production. This is not functional programming per se, but given that so many people mention recursion whenever they mention functional programming, it's worth listing recursion here. And mutual recursion and tail recursion, two of the hallmarks of entry-level functional programming techniques? Check and check. For instance, RxJava implements trampoline just to support tail-recursion, as it is necessary to implement cleanly some of RxJava's operators.

- Common techniques seen in functional programming, particularly the ones that involve map, reduce, scan, left-fold and right-fold. Check.

This is just the items that are on top of my mind. I'm sure I missed plenty. The gist is that people have been adopting functional programming. They just don't necessarily move to a purely functional programming language for practical reasons: platform, support, community, ecosystems, or even marketing. Programming paradigm is just one factor among many when people choose their programming languages.

One's missing out on a lot of advantages though, if one does not apply the paradigm quite broadly in a code base. Mostly referential transparency, how do you test your code, if you cannot be sure, that something is without side effects and have to check every single procedure? It takes away a lot of the appeal. If I write a program in functional style, I want some guarantees in return, which I don't get from half baked things. Easy testability, simple parallelization, composability of functions.

Who uses CPS in daily programming? Or do you mean using a compiler that uses it?

The Visitor pattern is not much more than a CPS-style transform that lets you represent sum types in a language without them.

A CPS transform for a computation of type `X` gives a computation of type `forall A. (X -> A) -> A`. That is, instead of evaluating to ("returning") a value of type `X`, you take a function that you deliver a valid of type `X` to, and return whatever it returns.

CPS-transforming a sum type `X + Y` gives `forall A. (X + Y -> A) -> A`, and if you distribute over the sum you get `forall A. ((X -> A) * (Y -> A)) -> A`. The visitor is the pair of functions you pass in, `(X -> A) * (Y -> A)`, and the value decides which method to call. In either event, it returns whatever the chosen visitor method returns.

(Dropping into Java syntax, this is the type of the `visit` method: `<A> A visit(Visitor<A> visitor)` -- and the Visitor is `interface Visitor<A> { A onX(X x); A onY(Y y); }`.)

I cannot claim it is, but async/await, at least in ES seems to be a continuation monad without the do notation.

Callback hell in JavaScript.

Definitely in compiler, but also in daily JavaScript as a way to avoid deeply nested callbacks.

I'm no expert but I think that the async-await pattern is quite similar to CPS.

And I forgot to mention all kinds of monads in various languages.

I think the second reason is probably more important. What languages were pushed by a big company but weren't a primary interface to a platform?

The only ones I can think of are Java and C#, which are very big languages, but combined they're dwarfed by these languages, which follow the second rule:

C (Unix), C++ (compatible with C), JavaScript (browser), Objective C (OS X and iOS), Kotlin (Android), bash (first program to run on the Linux kernel)

C# is a primary interface to the Windows platform.

Java is a primary interface to the Android platform (2008). When it was originally made decades ago (1996), it was supposed to be the first language for cross platform development (compile once run anywhere), it may not be one platform per se but it is equivalent in a way.

Yeah it's true that C# gives you more access to Windows than any other language, e.g. for GUIs and such. Java became popular without Android, but Sun was very much a platform company (Solaris -- they just didn't succeed in the long term.)

So basically the point is that the first reason is a special case of the second... Marketing alone does a little bit for a language, but having the platform is more important.

People choose platforms and not languages. Big companies are the ones that own platforms (Linux being an exception).

Oh right almost forgot about Solaris. ^^

I don't recall Solaris ever being any significant, so must have been a good argument that Java could run on the many Unix/Linux variants besides Solaris.

Solaris was huge, in the US at least, in the 90s.

I learned Unix and C on a SparcStation, and to this day I prefer workstations to other computers.

Even if Apple is the only one still making them...

When a desktop rivals some servers for power the workstation is dead.

Sure, you can swap the relative importance of those factors if you like. My point is that an expert's concept of "quality" is not indicative of market success -- in programming languages, or any other. The 25 best-selling albums of the year are probably not the 25 best musicians, either.

But I'll try to answer anyway: Go. Dart. Maybe Rust (depending on whether nonprofits count). Delphi. All of these are in the TIOBE top 25 today.

Furthermore, languages like Kotlin, Swift, and C# became a primary interface to their respective platforms, but didn't necessarily start out that way. They got popular, and then became first-class platform citizens. It may have been the plan for them to eventually become that from the start, but I would claim they would have become popular even without the platform. So I put them in the first group.

You can write Windows programs in C# today, and many developers do, but I bet even more are using it for web development. And in a popularity contest (Zipf's Law), losing even half of your fans won't change your list position much.

Go, Dart are pushed by Google, another big company.

Delphi was pushed by Borland, the InteliJ from the 90's, everyone doing indie development on MS-DOS and Windows early days was using Borland compilers, not Microsoft's.

Most Web development with C# is done on Windows anyway.

Functional programming main problem was its mathy roots (too dry, too abstract, too cryptic, too culturally alien). IMO.

Nobody (hyperbole) gives a damn about math, even though they'll all end up using the very same ideas in mainstream clothing.

It might not be obvious to half the dev crowd but most thing they're talking about since 5 years is basically 80s academic FP. Destruct, patterns, lambdas, folds ..

math: I found out that if your operation is XYZ then ABC nobody: hurray! ... few decades latter programmers: how the f* do we do paralle? math: ... programmers: shut up! NO! NOOOOOO!

- IT: we can't compute infinite data on finite machines !

- Cantor: smh


PHP do have its great niche.

Namely it's the only programming language where whole ecosystem lives and dies by the "build and burn the whole world on each request" mantra. It have significant advantages compared to other models of computation. (Granted even PHP devs often misplace "developer friendliness" of PHP, so you are not alone ;))

PHP was pushed by the LAMP platform and that was pretty much the only language to make dynamic web sites in the 1990s and onto the 2000s. (The alternative would be CGI scripts if I remember well?)

Ruby only has some popularity in the silicon valley. Never heard of companies really adopting Ruby outside of there. It's open to debate whether it can qualify as one of the popular languages.

PHP was popular before LAMP came along, if anything LAMP came about because PHP was so common.

Early on its key feature was easy hosting, there were a lot of shared host sites where using anything other than PHP or maybe a bit of Perl was difficult.

You could describe PHP as the primary interface to Apache. It would be straining the the metaphor a bit, but I'd say it's still a reasonable way to explain PHP's popularity. mod_php enabled shared hosting with reasonable performance. If mod_perl had been usable in an untrusted shared environment, then PHP might never have taken off the way it did.

Ruby is definitely big in Seattle -- I would say bigger than Python or PHP, but that could just be my circles. In the language popularity lists I've seen, it's typically in the #11-15 slot, which is not too shabby.

The "LAMP platform" is defined by the set of people using PHP/Perl, so I wouldn't call it "pushed" by that. It's not the native platform of Linux, Apache, MySQL, or the web, and there wasn't exactly any big company pushing it (Facebook famously uses it but it had already cemented its popularity by then).

I've used Racket for many prototype languages and tools and love its facilities and philosophy. The thing that always gives me pause when considering it for a new project is that it has no robust mobile or client-side web story.

If the tool lives on beyond prototype then I have to rewrite it in a native language or restrict it to the subset of Scheme that can run in Gambit on iOS.

I really hope that Racket can evolve and adapt to a world where more computing and even development is going to happen on mobile and web.

I keep looking at Gerbil Scheme as another “modern feeling” scheme with some opinions and creature comforts. And it’s built on Gambit.

I wish the team did away with Dr Racket... It does have some unique features but I feel like it adds megabytes to the whole package and is not really very usable for anything other than learning (imho). I've seen this acknowledged by the Racket docs I think (the fact that it is supposed to be a learning environment).

I suspect Racket would be a lot more popular as a development environment if the team did away with Dr Racket and put those resources into maintaining a very solid Emacs, Vim and VS Code integration.

> I wish the team did away with Dr Racket... It does have some unique features but I feel like it adds megabytes to the whole package

Just download the 'Minimal Racket' build instead. ~10MB instead of 100+

> I suspect Racket would be a lot more popular as a development environment if the team did away with Dr Racket and put those resources into maintaining a very solid Emacs, Vim and VS Code integration.

I think racket/gui would suffer if they stopped working on Dr Racket, which would be a shame.

racket doesn't have any less of a solid integration into emacs (racket-mode) and visual studio code (magic racket) than most other languages.

I don't think this is true. I don't think racket-mode has a big community around it, and sadly doesn't come even close to slime [1] or cider [2], both very feature full dev envs for Emacs.

Magic racket is very bare bones and can't compare to integrations like Calva [3].

So I saw someone down voted me... just to be clear, I use Racket despite having to work against a poor tooling experience, when comparing to say, CL or Clojure.

I want Racket to succeed in industry, so is not like I'm complaining. I'm pointing out what I think is a weakness, maybe a blind spot by the team, since they seem to be very attached to Dr Racket!

1: https://common-lisp.net/project/slime/

2: https://cider.mx/

3: https://github.com/BetterThanTomorrow/calva

Have you checked the new features recently?


So part of the problem is that racket mode has a bus factor of 1. I saw that the maintainer posted this [1] a while ago, which is a bit concerning.

My point is that would be ideal if the core Racket team also participated in polishing the IDE integrations, other than Dr Racket.

1: https://www.greghendershott.com/2019/07/future-of-racket.htm...

On the other hand, I've just spent several more-or-less full-time months taking advantage of the drracket/check-syntax library, provided by the core Racket team.

On the third hand, I spent all that time, so wrt "bus factor 1", there will be no pleasing you. :)

Just avoid buses please :-p

Thanks for all your work on the racket ecosystem!

Magic Racket author here. On one hand, it’s difficult to see such a big time investment into DrRacket and not think about what could have been if so many man-hours went into the language server instead...

But on the other hand, many things from DrRacket can be reused as modules in the language server, so the work that goes into it is not “lost” for the ones that don’t use it directly.

Also, what’s the biggest feature you miss from Magic Racket (and the language server by extension)? As far as I’m aware, the language server project doesn’t have a fixed set of goals and it grows rather organically. Maybe they would make use of this kind of feedback.

My first and only experience with MagicRacket was trying to run EOPL's code [1] (and failing), I filled this bug [1] and haven't tried again yet.

Should MR work fine with other langs? I don't think it is stated on the docs anywhere if this is a supported feature. For instance, if I open a .scm (Scheme) file, Ctrl-P to switch to lang (MR mode) and launch a REPL, is it supposed to work fine?

1: https://github.com/mwand/eopl3

2: https://github.com/Eugleo/magic-racket/issues/13

It should be fixed. Magic Racket works with other #langs as much as racket-langserver doe. That means, AFAIK, that if the #lang is configured correctly to work with DrRacket, it should work with the langserver as well.

you know, i actually take back my statement to a degree. i agree with you, especially on the examples you provided.

what i was thinking of is most languages. having used various ides for python, elixir, and f#, i have been rather unimpressed with IDE offerings from these languages. dr. racket is indeed nice and easy to use but is rather frustratingly un-performant. clojure's IDEs look so nice and clojure is very enticing, but i just don't want to live on the jvm and in java land.

Racket has some of the best documentation I've ever seen and is a joy to use. I don't use it, but DrRacket is also a great IDE -- especially for beginners.

I wish either Racket was more widely used in industry or I had more time/energy/excuses to use it.

Scribble documentation rendered as HTML is alright, but I wish there was better support for accessing that documentation in your editor. Racket Guide and Racket Reference are both very well written though.

In DrRacket, when the cursor is on an identifier, you can hover over the big arrow at the top right corner of the definition window. A popup will appear showing basic usage of functions / macros without detailed explanation. However, you can click "read more..." which will open up the full documentation in a browser. Also, this documentation is installed locally and does not require the internet.

The documentation is beautiful but is far from complete, API's lack examples and if you do a search there is confusion about which module the function refers to. I find Clojure and Common Lisp documentation quite complete for a lisp. I also find Ruby docs have tons of example code in its docs. Though I agree none is as beautiful as racket docs.

While I can certainly believe that more examples are needed, the second issue I don't understand. If you search for something, it tells you exactly what module it's from: https://docs.racket-lang.org/search/index.html?q=call-in-con for example.

Yeah, the "provided from <module>" part has been there for a long time.

Happy birthday!

Looking forward to Racket CS as main implementation.

The talks done by the Racket team are always interesting to watch.

Well this is a Birthday year for many languages. 1995 must be some super anomaly year Ruby, Java, Javascript, PHP, Delphi and Racket all were invented in the same year.

I don't think it's a coincidence that the mid-90s was a hot time for language design: the CGI-bin protocol of the Web suddenly made it possible to write code in any language you wanted and distribute the results, even with a loosely graphical interface, painlessly to clients (in the sense they didn't need to install anything). I call it the "Cambrian explosion of languages".

Though Racket was not created for that purpose, it's unsurprising that many others from that era were linked to the Web.

Perhaps you are right, I was just just 11 when these languages were invented so I really lack any context.

What I learned from studying Racket is that I can now only reluctantly forego functional programming languages in all contexts personal and professional.

Why forego at all? (-:

How does Racket compare to Clojure? Anyone knows both worlds and would like to give some infos? I know Clojure is JVM based, one of those new languages built on Java technology (the others being Scala and Groovy). So very solid tech used by the likes of Soundcloud or young startups like RoamResearch. But Racket? Mostly education?

There is very little commercial use of Racket. I've used it several times to make little GUI apps to deploy on multiple platforms, and it excels at that.

Probably the best way to think about the two of them is that Clojure is a focused language design, and the assumption is that you stay in the language and extend it with macros. Racket is an environment for generating languages. The assumption is that you will build language variants to do various tasks.

Very little commercial use of Racket is maybe an understatement. A few notes to people thinking about commercial use of Racket...

The big customer of my consulting business (public sector) did amazing "force multiplier" things with Racket and my help, even when many general-purpose libraries had to be built in-house. But there were virtually no other prospective clients in that niche after over a decade.

There are a few organizations who use Racket to great production effect. But two problems for consulting&employment for those:

* Their generally one-person teams could usually do everything that's needed, and perhaps some developers prefer that;

* When they would like additional help, they generally didn't have the money/authority to pay HCOLA developers.

I tried half-heartedly for a few years to promote the idea of doing one's startup prototype with Racket. But the browser-side and iOS&Android app stories aren't there yet. And my own startup, I self-funded too long before my co-founder and I realized we should've found a CEO to court funding months earlier.

The startup where I currently lead engineering uses (for historical reasons) Python for server backend and for device interfacing on a light embedded system, and framework-like JS on one frontend, and interfaces with a SaaS for a different frontend. All the Python bits could've been done in Racket, and Racket would've been more productive and fun to work with, but it's not worth rewriting at this time. I recently prototyped a new embedded system frontend in Kivy, and was able to get a running GUI mockup nice in a few hours, but realized afterwards it would've been better with Racket's GUI toolkit.

When I recently had to pick a method to do an iOS app that wasn't consumer-facing, I was tempted to use Gambit Scheme. But I decided on Swift and SwiftUI, to be safe, and so we'd have more experience with it for the next iOS app (consumer-facing, for a high-quality/prestige brand) that was more likely to need a more-native toolkit and APIs.

That said, if someday I have a startup that uses Racket or another Scheme (or another fringe platform), I expect the platform appeal to help me attract a larger pool of higher-powered developers than I otherwise could.

If you're considering using Racket for making money, one start is to participate in this low-traffic email list (which has some unusual conventions): https://www.neilvandyke.org/racket-money/

There isn't a lot of commercial use, but there's some.

Some of the more famous cases are game development for PS4, specifically Uncharted series and related from Naughty Dog studio. Some other places also do internal tooling in it (including John Carmack at Oculus)

Though this is not at all the only essential part of Racket, building other languages atop it is something Racket really specializes at, which Clojure does not. See http://cs.brown.edu/~sk/Publications/Papers/Published/fffkbm.... Of course, Clojure rocks running atop the JVM, with all the attendant engineering benefit that provides down below; Racket doesn't do that (and can't; its VM has to be specialized to support various control features, etc., that the JVM doesn't provide).

It seems functional programmers are alone in being able to take a joke. Long live Racket!

What is "the infamous Felleisen-Wadler paper"?

Based on context I would assume it is:

A Call by Need Lambda Calculus.

Zena Ariola, Matthias Felleisen, John Maraist, Martin Odersky, and Philip Wadler. 22'nd Symposium on Principles of Programming Languages, ACM Press, San Francisco, California, January 1995.

There is a humorous story about how the paper and collaboration came about, which Felleisen discusses in an interview [1].

[1] —> https://www.cs.cmu.edu/~popl-interviews/felleisen.html


Happy Birthday Racket! I’ve learnt a lot working with Racket and I hope that will continue: next on my list `#lang typed/racket` https://docs.racket-lang.org/ts-guide/quick.html

I feel like this article has a rather abrupt ending. Is there another resource that covers Racket's early history?

It's really just about the initial steps of the project. One talk you might like is https://www.youtube.com/watch?v=wEgaVMOYLEU from 9 years ago.

Quixotic CS professors probably were too fixated on Mothers' Day to remember their other anniversary. A cause for celebration!



There was a tradition of such self-deprecating names for lisp dialects specifically -- an early system called PLANNER had an offshoot which was named CONNIVER, and SCHEME itself was another branch off this tree (originally named SCHEMER, and truncated because the MIT AI lab's homebrew ITS timesharing system limited filenames to six characters). https://en.wikipedia.org/wiki/Scheme_(programming_language)

Also in that list is MDL or MUDDLE. This is the language that ZORK was written in.

Also Will Clinger's Larceny.

Or Stalin, the Scheme compiler that "brutally optimizes".


The question still stands if insider jokes are an efficient source of inspiration for naming your work.

"Eschew flamebait. Don't introduce flamewar topics unless you have something genuinely new to say. Avoid unrelated controversies and generic tangents."


Would you please stop posting unsubstantive comments? You've been doing it in this and other threads.

Fair enough.

The answer is: yes.

Some examples:

- Python comes from Monty Python

- Ruby is inspired by Perl but according Wikipedia chosen because of a bright stone used by one of the authors colleagues

- Smalltalk was chosen by Alan Kay to avoid a god-like name and lower expectations (see The Early History of Smalltalk)

- Lua is a Portuguese word for Moon, because of a previous project named SOL (sun)

I can continue with Pascal, Ada, and Haskell based on people names. Also with Java (maybe inspired by a coffee store), C (which is not even a word), D...

The point is: systems and programming languages are made by people. Good naming is important for function/operators/libraries because they play a part in system comprehension. But, otherwise having a “fun” name reflects the humane part of the creation :)

SOL does indeed mean "Sun", but was actually an acronym for "Simple Object Language". It in turn was the successor to DEL (defined as a "dialog specification language", but that would be DSL in English or LED in Portuguese so I haven't figured that out). Anyway, having an acronym that is also a relevant word or name is a popular thing to do.

The Wolfram Language is named after the author. The closest to that I can think of is Algol-W by Niklaus Wirth and Tony Hoare (that is if the W is for Wirth at all, which I couldn't verify). Are there any other cases?

Another case is AWK named after the surnames of the authors.

"I would recommend not wasting any more time on the naming issue. (This is a recurring theme in my posts -- remember, I spent about 0.3 microseconds thinking about whether "Python" would be a good name for a programming language, and I've never regretted it.)" -- Guido van Rossum, 25 Nov 1998.

It's a catchy name that's fun to say. Being an amusing pun only makes it better. So the answer is yes, it's a wonderful name for a scheme.

The name MrEd was also an in-joke because Matthias Felleisen was notoriously anti-TV, so his students thought it fun to sneak in a TV reference.

Lots of the old subsystems had prefixed-names. MrEd and MzScheme begat DrScheme; others include SrPersist (Sister Persist) and FrTime (Father Time). We built a debugger called MzTake ("when you make a mistake, use MzTake"). My favorite is an IRC client that Robby Findler wrote called MzCommunication.

It wasn't from "day one". The name Racket is only about 10 years old. It started life as PLT Scheme.

A racket is a kind of scheme.

EDIT: You've edited your post to include more ridiculous assertions.

Python was literally named after Monty Python.

You know what, whatever, I'm not playing this stupid game.

> A racket is a kind of scheme.

That's hilarious. It only took me 5 years to get.

Guile makes sense now too.

'Gambit Scheme' has a similar style of name.

Gambit Scheme is also a pun on Marc Feeley's surname in Irish -- O Fithcheallaigh -- which means 'chess player'. The name is derived from the ancient Irish board game fidchell, rules unknown, but taken to be akin to chess.


That's a bit different. Guy Steele's first Scheme compiler was called RABBIT (it ran fast). The Yale T project created the Orbit compiler. This set off a *bit trend, including Gambit and also Will Clinger's Twobit.

In fact, that's clarified in the very next sentence of the article.

You are right that I removed in sentence because I read to quick but the whole article is about naming. Is it so strange to comment on specific names? I don't think the authors could have done worst.

Synonyms for racket: haphazardness, disagreement, noise, stochasticity, interference, dissonance, dissension, fraudulent scheme, disturbance, randomness, illegitimate enterprise.

You don’t think they could have done worse? I present to you “Brainfuck”.

This is an odd hill you’re choosing to die on.

I mean, the creators of Brainfuck weren't exactly aiming for widespread adoption.

> fraudulent scheme

It's a joke.

You know it's also the name of a sporting good, right? There's this game called tennis. Quite popular, can be fun to play and to watch. You should check it out.

I don't know why "application performance" is brought up here, do you mean adoption?

I think Racket is a pretty bad choice, I'm from Italy and here you find that word in news about mafia and organized crime, so imagine the kind of association it bears with it.

Naming things is hard, but sometimes hackers seem to choose to make it harder... https://racket-lang.org/new-name.html

I'm also from Italy and you know perfectly well that nobody even aware of the existence of Scheme dialects would be confused by this.

And what about people without any knowledge of Scheme dialects? (Let's call them, for the sake of brevity "CS juniors".)

Consequently, Doom and Quake are banned from your household in favor of Animal Crossing?

I presume you refuse to play tennis, then, solo calcio.

Uhm, I wonder how would people from this village comment on it https://en.wikipedia.org/wiki/Fucking,_Austria

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact