Skip to content

Getting Started

Archer edited this page Jun 18, 2017 · 4 revisions

Installation

The easiest way to install Desmond is with composer, so that's what we'll do. You can also just clone the repo for the latest development version.

composer require archer70/desmond
composer install

Quick Guide

Desmond, being a Lisp, is quite an easy language to learn, as the syntax is extremely simple. This is due to the fact that language structure and data are treated as if they are the same thing.

Start up a REPL (Read, Eval, Print, Loop) to follow along.

$ vendor/bin/desmond --repl

Once you've got a REPL fired up, you can write the following code examples into it to get their output.

Numbers

Desmond is capable of recognizing both whole and decimal numbers.

7
4.20

Strings

Strings are a series of characters surrounded by double quotes. Anything between those quotes will be recognized as one piece of data.

"This is a piece of textual data."

If you wish to have a string that contains a double quote, you'll need to escape it with a backslash.

"This is a string with a \"double quotes\". "

Symbols

Symbols are pieces of data that are most often used as placeholders for something else. Much like in math, where you can write X = 7, and then refer to X as if it is 7. We'll get into defining symbols later, but for now you can try writing one into the REPL.

my-symbol

You can see that it evaluates to itself if it has not been assigned another value.

Symbols can also contain special characters to help express their meaning.

  • my-symbol
  • :my-symbol
  • my_symbol
  • mySymbol!
  • my-symbol?

You'll often see symbols prefixed with a colon (:) under certain circumstances. Usually when used as a function argument or Hash key. More on those things later.

True, False and Nil

True and False are basically what they sound like. They are boolean values that are most often used to decide if some condition is true or false. A real life example would be if you were to ask a friend if a cow is an animate object. They would reply true. Whereas if you asked if a hammer was an animate object, they'd say false (unless they're stupid.)

true
false

Nil is a bit more vague, because it literally means "nothing." It is used to describe something that has no value.

nil

Vectors

A vector is a fancy name for an collection of stuff. The stuff being other Desmond data types, possibly including more vectors. They are defined by using opening and closing square brackets.

Here's an example of an empty vector.

[]

And one with a few numbers in it.

[1 2 3]

And another with a bunch of random types.

[my-symbol 2 "three" nil]

Vector values can be retrieved by their numeric index using the nth function (starting from 0).

(nth ["one" "two" "three" "four" "five"] 2)
;#> three

Hash

A hash is another collection of data, much like a vector, with one key difference. Hashes are pairs of keys to values. That is a Hash must contain an even number of arguments, where every odd value refers to the next even value.

Empty hash.

{}

Hash with one key=>value

{:name "Desmond"}

Values can then be retrieved by their key using the get function.

(get {:key "value"} :key)
;#> value

Functions

Functions are pieces of data that store code to execute at a later time. Desmond has quite a few core functions that you can use, such as + and print. When a function is passed as the first argument of a List, it is executed and passed the rest of the arguments as its parameters. The best way to describe this is with an example.

(+ 1 2 3 4)
;#> 10

In this case, we're calling the + function, which takes all the number arguments and adds them in sequence. In other languages, this would look more like 1 + 2 + 3 + 4.

Lambdas

Lambdas are special functions that you define, but don't necessarily call right away. And, interestingly, you use a function (lambda) to do so.

(lambda [name] (print-line "Hello, " name))
;#> <#function>

Here we've declared an anonymous function (doesn't have a name). The first argument is a Vector, which we've seen. It lists the Symbols that the function is using as parameters. The second argument is the body of the function to execute when you call it. In this case, it's the print-line function that uses those symbols we just listed.

Now you'll notice that the return value isn't the printed string "Hello, name", it's actually the function itself. What we're going to do now is actually execute the function.

If you recall, if the first argument of a List is a function, it will execute said function. So lets do that now, and pass the String "Desmond", which will be bound to the name symbol listed in the arguments Vector.

; Multi-line code won't work in the REPL at this time.
; I've expanded it for ease of reading,
; but you can condense it to one line and run it.
(
  (lambda [name]
    (print-line "Hello, " name)
  )
  "Desmond"
)
;#> Hello, Desmond

State

In our final examples, let's look at binding data to Symbols using the define and let functions.

We can define a function as above and make our symbol say-hello refer to it for later use.

(define say-hello (lambda [name]
  (print-line "Hello, " name))
;#> <#function>

(say-hello "Desmond")
;#> Hello, Desmond

This also works for other things

(define X 10)
;#> 10

(+ X 5)
;#> 15

And next we have let, which is slightly more complicated. First, let's start with an example.

(let
  {name "Desmond"}
  (print-line "Hello, " name))
;#> Hello, Desmond

In this example, the let function takes two arguments. The first is a Hash, which as usual, takes key>value pairs of data to be used in the second argument. This is actually similar to how Lambdas work, except you're defining the data up front.

The other major difference is that let's data definitions are limited to the scope of the let function. That is, anything defined in the Hash will only be accessable inside of that let. Another example is in order.

(let {new-name "TehCraw"} (print-line new-name))
;#> TehCraw

(print-line new-name)
;#> new-name

Clone this wiki locally