
… so that, in particular, starting racket with just racket/base would be faster.

That said, we could well have a racket/core
or racket/base-small
or whatever that is even smaller, while keeping racket/base
.

(meta question) I’m making a #lang
and would like to discuss it and get feedback and ideas for improvements/additions. I think that just saying, “look at this big project and tell me what you think” is probably not a great way to start a useful discussion, but I’m new to language design and don’t have an intuition for this. What things could I focus on to facilitate the discussion?

I think giving specific use cases before explaining anything else helps a lot when discussing languages (and also libraries and frameworks)

Language design is a huge space and exploring it with people is way easier if those people have a roughly shared understanding of their goals

and I like using use cases as goals because otherwise people tend to pick abstract goals that are easy for other people to misunderstand and which are missing a lot of context

The lang I’m making is, essentially, a combination of smaller, separate ideas that I’ve been considering for a while: • A core language smaller than racket/base
. • “Tidy” and “modern” APIs. • Bind with patterns, instead of variables. • Emphasize pattern matching. • Surface syntax that uses fewer parens, but is still based on s-exprs. • (gently) enforce separation of “pure” and “impure” code. • Emphasize immutable data and higher-order/functional programming. • Use generic operations throughout the stdlib. • Be expressive enough to be useful on its own. • Be able to cooperate with existing Racket libraries, if needed/desired.

Many of my goals have been explored/implemented separately in Racket libraries and langs. Since I’m trying to achieve all those goals in one lang, some of my work is putting together or wrapping existing things and some of my work is building something that fits well with the other parts.

Since those goals are really broad and vague, I can elaborate on them, individually, and provide examples of what I’d like things to look like.

Is there any reason why these layers cannot be added?

Migration work is the main obstacle. If racket created a new racket/XXX
module every year it’d drive people up a wall.

I like all those things

a weird thing I’ve encountered with “bind with patterns, instead of variables”: you can’t use define
to mean both “bind variables” and “create a function” anymore

Because of the syntactic changes I’ve included, my define
form is still able to do double duty.

Also, racket/base
is pretty small, and things you could cut would either not help much (like filter
, say) or be a big step down in functionality (like for
).

I’m less sure a smaller racket/base
would be that helpful — a smaller “base” package would be very nice, but that would just be a lot of re-implementation work.

Oh neat, what did you change?

As an example, this is the factorial function, in my language: {define fact : {-> natural? natural?}
(fact n) ⇒ (fact-acc n 1)
#:where (fact-acc n acc)
⇒ {if (= 0 n)
acc
(fact-acc (sub1 n) (* n acc))}}

ah so it’s using the haskell-y where
thing for locals defined after their use sites?

Yes, the #:where
clause is translated into a define
in the underlying Racket procedure body, before the result expression.

What do the curly braces mean?

Unlike Racket, different delimiters have different meanings. (Unless overridden by a macro) parens are for procedure application and braces are for syntactic forms.

are parens also for pattern matching?

to me, the main benefits of making racket/base
smaller is avoiding identifier conflicts

it’s very difficult for libraries to provide things with the same name as any of the exports of racket/base
without breaking stuff

usually scribble docs, in my experience, since they’ll do (require (for-label racket/base some-library))

The define
form expects a function header in parens, so that it looks like a function call. Since match-expanders (patterns) are syntax, they are written with braces in expressions. For symmetry, forms that use matching also expect patterns to be written with braces.
example: {define (flip {list a b}) ⇒ {list b a}}

Is that {list b a}
expression on the right a function application?

No, that’s a pattern for list-building. One radical thing I’ve done is eliminate (quasi)quotation for list matching and building. Instead, I provide a match expander that uses a new syntax for lists.

(Part of the modernization is removing lists from their position as the central datatype.)

Although my language is currently implemented as Racket macros, I plan on switching to using <https://docs.racket-lang.org/ee-lib/index.html#%28part._top%29|the “ee-lib”> and building a self-contained core language that is compiled into Racket.