Racket for the Masses

Table of Contents

1. Introduction

2. Racket in 20 minutes or less

2.1. How to use functions

While functions in any other language look like this string_append("a", "b", "c"), in Racket they are written (string-append "a" "b" "c"). The open parenthesis is put before the function name and there is no comma separating arguments.

Play close attention to that because everything else is based on that format. In general, to call a function the format is:

(function-name arg1 arg2 arg3 ...)

2.2. Things that are not functions look like functions

2.2.1. Math looks like functions

Math has no special representation nor it changes the way the code is normally evaluated.

So, this in most languages:

1 + 2 + 3 * 4 * 5

Is written in Racket like this:

(+ 1 2 (* 3 4 5))

2.2.2. Control structures look like functions

Other languages have “commands”, reserved words, and special syntaxes for control structures. There is no such things in Racket. For example, if is usually reserved in other languages and have a special structure:

In Ruby, it is:

if a == b
  1
else
  2
end

Or in Javascript:

a === b ? 1 : 2;

The equivalent in Racket is:

(if (= a b) 1 2)

Note that it looks exactly like a function call.

2.2.3. Variable assigment looks like functions

A variable assignment (called binding in Racket) usually has a special structure in other languages. In Racket they look like functions, as everything else.

Variable assignment in Ruby:

a = 1

In Racket:

(define a 1)

2.2.4. Function definitions also look like function calls

Any other language have well defined syntaxes and reserved keywords for defining functions, methods, classes and so on.

For example, a function in Python is defined like this:

def add1(a):
    return a + 1

add1(10)

In Racket, defining a function looks like we are just calling the function define:

(define (add1 a) (+ a 1))
(add1 10)

2.2.5. Anonymous functions look like functions

Anonymous functions or code block in other languages also have special syntaxes. For example, a code block in Ruby looks like this:

add1 = -> a { a + 1 }
add1[10]
11

In Racket they still look like functions:

(define add1 (lambda (a) (+ a 1)))
(add1 10)

Or using the character “λ” instead of the word “lambda”.

(define add1 (λ (a) (+ a 1)))
(add1 10)
11

However, for simple functions like that, it is common to just use currying.

(define add1 (curry + 1))
(add1 10)
11

2.2.6. We call them “forms”

Given that the syntax for functions and everything else looks exactly the same, we need a name for them. In Racket they are called forms.

2.3. Function are just variables

2.3.1. They are cheap

  1. It is common to use them to reduce nesting

2.3.2. They are passed as arguments or attributed to variables

2.4. Polymorphism was introduced later

Racket is a Scheme-like language which is quite old. So old that is predates polymorphism or method/function overloading. That means we still have a lot of functions that are prefixed by the type of data they act upon.

For example, to get the second value of:

  • A list: we can write (list-ref my-list 1)
  • A vector, we should write (vector-ref my-vector 1).
  • A hash, it would be (dict-ref my-dict 1).

However, now Racket supports polymorphism and modern code can use functions like:

  • (sequence-ref anything 1) if we use the standard library.
  • (ref anything 1) if we use the excellent Generic Collections library.

2.5. Peculiarities

2.5.1. There is a small set of symbols that are reserved: () [] {} # |, everything else can be overwritten.

2.5.2. The language uses dashes for separate words in identifiers, like string-append or vector-ref.

2.5.3. There is no operator for “not equal” like !=. Conditionals have an inverse counterpart (like when and unless), we use (not x), (negate f), or just the structure the code to avoid the negation.

3. Programming Language Oriented

3.1. Create the language to solve your problem

3.2. All languages are interoperable

3.2.1. Each file is a different language

  1. The truth is, a file is a module

3.3. Do not be afraid of Macros

3.3.1. They are a basic component of Racket

3.3.2. They are cheap, done in compiling time

3.3.3. They can be difficult to debug, so keep them short

  1. If you using them locally, do not refrain yourself
  2. If you are building a library, spend time making them bullet-proof and on error messages.

Author: Ronie Uliana

Created: 2022-03-15 Tue 09:50