Racket is quite good for leetcode problems. It is functional but you can still quite comfortably write imperative programs (e.g. imperative data structures such as o(1) access arrays). The default installation of Racket comes with most of the basic data structures you need, and I haven’t run into a single instance where I would need an external library that Leetcode doesn’t import.
The special syntax for loops and iterations are, in my opinion, the most important features of a functional language. They make functional folds and maps tolerable so you won’t feel too frustrated to fallback to imperative updates.
Typed racket is even better. Occurrence typing means you have to write more type annotations than you are comfortable with if you are used to a hindley-milner style system, but the untagged unions make the code easier to refactor for small to medium sized programs on leetcode. Occurrence typing also supports some basic flow-sensitive analysis which you only see in systems with fancy types (e.g. GADTs or full-fledged dependent types).
The only situations where i used untyped racket are when the exercise is too simple or there are more runtime errors not enforced by the type checker that i would need to worry about than static type errors.
What surprises me a lot is that typed racket is indeed faster than untyped racket in many scenarios, with the only exception being problems that are so simple that the overhead of type checking outweighs the cost of the algorithm itself.
You can use the following hack to write any officially supported Racket dialects on Leetcode, including R6RS and lazy racket.
Suppose Leetcode asks you to implement the following function foo
.
(define/contract (foo x)
(-> string? string? ))
The code will be passed to an environment that uses #lang racket
,
the default untyped racket language.
To write foo
in typed racket, we wrap foo
inside a submodule M
,
which can use any dialect it wants, and then load the submodule from
the outside.
;; The name M doesn't have any special meanings
(module M typed/racket
;; export foo so it's brought to scope when required
(provide foo)
;; typed racket definition of foo
(: foo (-> String String)
(define (foo x)
... ))
(require 'M)
;; now foo is available!
Since typed racket functions can be directly called by untyped code,
leetcode will happily accept the program snippet. When untyped code
calls foo
, which is from a typed module, Racket will perform dynamic checks to
ensure that foo
does take a String
as its input.
Of course, you can use the same trick to write lazy racket.
(module M lazy
(provide foo)
;; define foo in lazy racket
(define (foo x)
(+ x 1)))
;; need to do some extra work to force the output of lazy racket functions
(require (prefix-in M: 'm))
(define (foo x) (force (M:foo x)))
No lol
While Racket is available on Leetcode, I don’t see it being supported anywhere on the online coding platforms that companies use. I’ve started writing a bit more OCaml because it’s supported on code signal with the batteries library preloaded.