[untitled]

    ; Lambda Calculus
    ; ---------------

    ; Lambda Calculus is a form of programming in which there are two basic
    ; operations:
    ; 1. Defining a function that accepts one argument and returns one argument.
    ;    Markup: [lambda][variable].[return expression]
    ; 2. Executing a lambda expression on another lambda expression:
    ;    Markup: ([function] [argument])

    ; Examples:
    (define identity (lambda (a) a))
    (define second-argument (lambda (a) (lambda (b) (lambda (c) b))))
    (define another-example (lambda (f) (f f)))

    ; Note that as in Scheme, the returned lambdas remember all the variables
    ; with which they were called. So for example:
    (((second-argument 5) 6) 7)
    ; Will propagate into:
    ; (lambda (b) (lambda (c) b)) while remembering that a = 5
    ; And in turn into
    ; (lambda (c) b) while remembering that a = 5 and b = 6
    ; And into
    ; b while remembering that a = 5 and b = 6 and c = 7
    ; Which is in turn equal to 6

    ; Currying:
    ; ---------
    ;
    ; We can create functions of more than one argument in Lambda Calculus
    ; using a technique called Currying. What it means is that instead of having
    ; one function that accepts several arguments, we have several nested
    ; lambdas.
    ;
    ; Here's an example:
    ;
    ; Instead of writing:
    (define my-func
        (lambda (x y)
            (+ (* 2 x) (* 3 y))
        )
    )

    ; and invoking it with
    (define ret (my-func 5 6))

    ; We can define:

    (define my-func
        (lambda (x)
            (lambda (y)
                (+ (* 2 x) (* 3 y))
            )
        )
    )

    ; and invoke it with
    (define ret ((my-func 5) 6))

    ; I.e: by making one function call for every argument.

    ; This technique simplifies the lambda calculus grammar and allows
    ; us to only deal with functions (and function calls) of one argument