Racket is an excellent programming language. It’s actually “a programming language programming language” or, in other words, a programming language to create programming languages.
However, to anyone used to Ruby or Python, it seems rather “raw”. At first glance, you have a collections API that’s not really ergonomic, no good date/time API, no multimethods, no static typing (no, wait, that’s actually not a problem)…
At first glance, I said! ;)
When you learn to use the right things™ instead of the first thing you learn™, Racket is a language as pragmatic as any of those cited above.
Few external libraries
As any other language, a few external libraries become “de facto” standard libraries, think OTP for Erlang or ActiveSupport for Ruby.
To install an external library (package) type in the command line:
> raco pkg install the-package-name
Here the list of essential packages for Racket:
- Threading Macros (package name: threading), by Alexis King. It provides threading operators from Clojure, just easier and more flexible.
- Gregor (package-name: gregor), by Jon Zeppieri. Excellent date/time library with everything you need. The “period” functions and structs worth it.
If you are feeling fancy, you can use Generic Collections (package-name: collections), by Alexis King. It’s really nice and works like a charm. Also, if you miss ordered hashes, the package Simple, Deterministic Dictionaries (package name: ddict), by Andrew Kent, is an excellent alternative.
Using the right functions
Most of the time, lists and hashmaps will do what you need. However, sooner or later you will need vectors or more sofisticated data structures. Then, things become ugly.
Also, if you are not fond of “string=?” try “equal?”. It works for strings, numbers, lists, hashes and a lot of other things.
A helper function or two
Often you have a function that’s pretty much what you need, but you don’t like its name or arguments.
No problem, just define them:
(define (sequence-first seq) (sequence-ref seq 0))
(define (sequence-rest seq) (sequence-tail seq 0))
Or, if you are using threading macros:
(define sequence-first (λ~> (sequence-ref 0)))
Actually, I redefine “first” and “rest” in terms of sequence. It’s far more ergonomic than the original “first” and “rest” (which work only for lists).
(define first (λ~> (sequence-ref 0)))
(define rest (λ~> (sequence-tail 0)))
Also, it’s possible to rename functions as you require them. That means it’s possible to forget the standard “map” function (that also works only for lists), and replace it by “sequence-map”.
(require (rename-in racket/sequence [sequence-map map]))
Yes, I rename a lot of functions in favor of the ones that use generic interfaces. Just be aware it can be a little confusing to anyone not used to your code.
Racket is awesome in day-by-day programming and it’s getting better as time passes. Plus, it has A LOT of really useful things you can’t easily find in other languages, start with macros and plots (far better than “matplotlib”, IMHO), if you want a glimpse of them.