Update doc/introduction.md
This commit is contained in:
parent
802558bf3e
commit
8ccb8e17ae
|
@ -28,6 +28,7 @@ And that's awesome.
|
||||||
### Ludus is expression based
|
### Ludus is expression based
|
||||||
Ludus has no statements, only expressions.
|
Ludus has no statements, only expressions.
|
||||||
Every expression returns a value, including conditional forms like `if`, `when`, and `match`.
|
Every expression returns a value, including conditional forms like `if`, `when`, and `match`.
|
||||||
|
That said, not every kind of expression can go anywhere.
|
||||||
|
|
||||||
In Ludus, different types of expressions are called _forms_, riffing on the grand Lisp tradition.
|
In Ludus, different types of expressions are called _forms_, riffing on the grand Lisp tradition.
|
||||||
|
|
||||||
|
@ -40,16 +41,16 @@ Ludus has the following types:
|
||||||
* `:bool`: Boolean--`true` or `false`.
|
* `:bool`: Boolean--`true` or `false`.
|
||||||
* `:number`: IEEE-754 64-bit floating point numbers. Ludus does not have an integer type. That said, Ludus avoids `NaN` as much as possible.
|
* `:number`: IEEE-754 64-bit floating point numbers. Ludus does not have an integer type. That said, Ludus avoids `NaN` as much as possible.
|
||||||
* `:string`: UTF-8 strings.
|
* `:string`: UTF-8 strings.
|
||||||
* `:keyword`: Keywords are self-identical atoms, evaluating only to themselves. The equivalent of a `Symbol` in Javascript (or a keyword in Clojure or Elixir). (The types in this list--and in Ludus--are represented as keywords.)
|
* `:keyword`: Keywords are self-identical atoms, evaluating only to themselves. The equivalent of a `Symbol` in Javascript (or a keyword in Clojure or an atom in Elixir). (The types in this list--and in Ludus--are represented as keywords.)
|
||||||
* `:tuple`: Fixed-length, fully immutable collections of zero or more values. Tuples are comma-or-newline separated values, surrounded by parentheses: `(1, 2, 3)`.
|
* `:tuple`: Fixed-length, fully immutable collections of between zero and 7 values (inclusive). Tuples are comma-or-newline separated values, surrounded by parentheses: `(1, 2, 3)`.
|
||||||
* `:list`: Persistent, immutable ordered list of any number of Ludus values. Lists are comma-or-newline separated values, surrounded by square brackets: `[:foo, :bar, :baz]`.
|
* `:list`: Persistent, immutable ordered list of any number of Ludus values. Lists are comma-or-newline separated values, surrounded by square brackets: `[:foo, :bar, :baz]`.
|
||||||
* `:dict`: Persistent, immutable associative collection of keyword keys and any Ludus values. Dicts are comma-or-newline separated keyword-and-value pairs, introduced by `#{` and closed with a curly brace: `#{:a 1, :b 2}`.
|
* `:dict`: Persistent, immutable associative collection of keyword keys and any Ludus values. Dicts are comma-or-newline separated keyword-and-value pairs, introduced by `#{` and closed with a curly brace: `#{:a 1, :b 2}`. Keys may be keywords or strings.
|
||||||
* `:fn`: Functions!
|
* `:fn`: Functions!
|
||||||
* `:box`: A holder for any value, which can change over time. A cognate of Clojure's atom. This is the only place in Ludus you will find mutable state.
|
* `:box`: A holder for any value, which can change over time. A cognate of Clojure's atom. This is the only data type in Ludus that can hold mutable state.
|
||||||
|
|
||||||
At current, three other types are planned but not implemented: `:set`, `:pkg`, `:process`.
|
At current, three other types are planned but not implemented: `:set`, `:pkg`, `:process`.
|
||||||
|
|
||||||
Ludus does not allow creating new types.
|
Ludus does not allow creating new nominal types.
|
||||||
|
|
||||||
### Ludus has a weird comment character
|
### Ludus has a weird comment character
|
||||||
It uses the ampersand--`&`--to introduce comments.
|
It uses the ampersand--`&`--to introduce comments.
|
||||||
|
@ -124,8 +125,7 @@ panic! "oh shit"
|
||||||
```
|
```
|
||||||
`panic!` may only take a single value, but that value can be a collection.
|
`panic!` may only take a single value, but that value can be a collection.
|
||||||
|
|
||||||
**Eventually** (not long from now!), Ludus will have actor-style concurrency, and a panic will only bring down a process.
|
Panics bring down processes, and any linked processes. More on processes below.
|
||||||
But this is not yet implemented.
|
|
||||||
|
|
||||||
### Almost everything is a function
|
### Almost everything is a function
|
||||||
Ludus does not have operators.
|
Ludus does not have operators.
|
||||||
|
@ -143,9 +143,10 @@ Everything you'll want to do with Ludus involves the Prelude in some way.
|
||||||
Note that most Prelude function names can, in fact, be shadowed by local bindings in a script.
|
Note that most Prelude function names can, in fact, be shadowed by local bindings in a script.
|
||||||
That said, there are several functions that, for optimization reasons, are "builtin," whose names may never be used, e.g., `add`, `sub`, `eq?`, `inc`, `dec`, and so on.
|
That said, there are several functions that, for optimization reasons, are "builtin," whose names may never be used, e.g., `add`, `sub`, `eq?`, `inc`, `dec`, and so on.
|
||||||
|
|
||||||
#### Boolean functions are "special forms"
|
#### Boolean "functions" are actually "special forms"
|
||||||
`and` and `or` are special, in that they are compiled differently than other functions.
|
`and` and `or` are special, in that they are compiled differently than other functions.
|
||||||
Their arguments are evaluated lazily, rather than eagerly, so they can short-circuit (and prevent panics).
|
Their arguments are evaluated lazily, rather than eagerly, so they can short-circuit (and prevent panics).
|
||||||
|
Because of that, they may not be referred to or passed around like other functions.
|
||||||
|
|
||||||
### Ludus lists and dicts are persistent
|
### Ludus lists and dicts are persistent
|
||||||
Dicts and lists are persistent.
|
Dicts and lists are persistent.
|
||||||
|
@ -176,7 +177,7 @@ But with two caveats.
|
||||||
|
|
||||||
(Before the caveats: you can put newlines before `then` and `else`.)
|
(Before the caveats: you can put newlines before `then` and `else`.)
|
||||||
|
|
||||||
#### Falsy falues: `nil` and `false`
|
#### Falsy values: `nil` and `false`
|
||||||
The condition (`foo` in the example above) is evaluated not strictly as `true` or `false`.
|
The condition (`foo` in the example above) is evaluated not strictly as `true` or `false`.
|
||||||
Ludus "falsy" values are `nil` and `false`.
|
Ludus "falsy" values are `nil` and `false`.
|
||||||
Everything else is truthy, including `0` and `()` (the empty tuple), and `""` (the empty string).
|
Everything else is truthy, including `0` and `()` (the empty tuple), and `""` (the empty string).
|
||||||
|
@ -189,7 +190,7 @@ If you want to throw away a value, you can do that, but you'll need something li
|
||||||
|
|
||||||
#### The `when` form
|
#### The `when` form
|
||||||
If you have multiple conditions you'd like to chain together, `when` forms are what you want.
|
If you have multiple conditions you'd like to chain together, `when` forms are what you want.
|
||||||
(Ludus does not have an `else if` form.)
|
(Ludus does not have an `else if` form, although you can certainly chain `if` forms together.)
|
||||||
`when` puts multiple clauses together, each of which has a left-hand condition expression and a right-hand body expression: `<condition expr> -> <body expr>`
|
`when` puts multiple clauses together, each of which has a left-hand condition expression and a right-hand body expression: `<condition expr> -> <body expr>`
|
||||||
Ludus will evaluate the left-hand expression, and, if it's truthy, evaluate and return the corresponding right-hand expression:
|
Ludus will evaluate the left-hand expression, and, if it's truthy, evaluate and return the corresponding right-hand expression:
|
||||||
```
|
```
|
||||||
|
@ -255,11 +256,11 @@ if true
|
||||||
:nothing
|
:nothing
|
||||||
} &=> :third
|
} &=> :third
|
||||||
```
|
```
|
||||||
Blocks can go most anywhere expressions can go.
|
Blocks can go most anywhere single expressions can go.
|
||||||
|
|
||||||
### Ludus has synthetic expressions
|
### Ludus has synthetic expressions
|
||||||
We have already seen function calls, e.g., `add (1, 2)`.
|
We have already seen function calls, e.g., `add (1, 2)`.
|
||||||
This is a _synthetic_ expression, which is a chained combination of bound names, tuples, and keywords.
|
This is a _synthetic_ expression, which is a chained combination of bound names, tuples, keywords, and method calls (more on these below).
|
||||||
The root of a synthetic expression may be either a name or a keyword.
|
The root of a synthetic expression may be either a name or a keyword.
|
||||||
Subsequent terms must either be tuples or keywords.
|
Subsequent terms must either be tuples or keywords.
|
||||||
They are evaluated by applying the second term to the first, then applying the third term to the result of that first application, and applying the fourth to the second result, and so on.
|
They are evaluated by applying the second term to the first, then applying the third term to the result of that first application, and applying the fourth to the second result, and so on.
|
||||||
|
@ -272,6 +273,13 @@ This accesses `:bar` on `foo`, applies the arguments `(1, 2)` to that value (pre
|
||||||
|
|
||||||
#### Keywords may be called as functions
|
#### Keywords may be called as functions
|
||||||
Following Clojure's example, you may call a keyword as a function: `foo :bar` and `:bar (foo)` are strictly equivalent.
|
Following Clojure's example, you may call a keyword as a function: `foo :bar` and `:bar (foo)` are strictly equivalent.
|
||||||
|
Keywords may also be called when they are not keyword literals but bound names, e.g., this is valid:
|
||||||
|
|
||||||
|
```
|
||||||
|
let foo = :foo
|
||||||
|
let bar = #{:foo :baz}
|
||||||
|
foo (bar) &=> :baz
|
||||||
|
```
|
||||||
|
|
||||||
### Ludus has function pipelines
|
### Ludus has function pipelines
|
||||||
In addition to normal function application, Ludus also has function pipelines, equivalent to Elixir's pipelines or Clojure's thread macros.
|
In addition to normal function application, Ludus also has function pipelines, equivalent to Elixir's pipelines or Clojure's thread macros.
|
||||||
|
@ -352,6 +360,7 @@ fn foo? {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Ludus will print the documentation for a function by means of the `doc!` function.
|
Ludus will print the documentation for a function by means of the `doc!` function.
|
||||||
|
`doc!` will also display all the patterns in a function's clauses.
|
||||||
|
|
||||||
### Ludus has a convention of "commands": they end with a bang
|
### Ludus has a convention of "commands": they end with a bang
|
||||||
By convention, Ludus functions that end in an exclamation point have side effects.
|
By convention, Ludus functions that end in an exclamation point have side effects.
|
||||||
|
@ -383,15 +392,14 @@ fn fact {
|
||||||
fact (6) &=> 720
|
fact (6) &=> 720
|
||||||
```
|
```
|
||||||
The difference between these is that Ludus will throw a compile error if `recur` isn't in tail position.
|
The difference between these is that Ludus will throw a compile error if `recur` isn't in tail position.
|
||||||
In addition, all clauses in a loop form, and all invocations of `recur` must have the same arity, whereas functions may have clauses of arbitrary arity.
|
In addition, all clauses in a loop form, and all invocations of `recur` must have the same arity and may not have splats in patterns, whereas functions may have clauses of arbitrary arity.
|
||||||
|
|
||||||
### Ludus has multiple "levels" of expressions
|
### Ludus has multiple "levels" of expressions
|
||||||
Not all Ludus expressions can appear anywhere you need an expression.
|
Not all Ludus expressions can appear anywhere you need an expression.
|
||||||
Ludus has four levels of expressions that restrict where they may go: simple, nonbinding, expressions, and toplevel.
|
Ludus has four levels of expressions that restrict where they may go: simple, nonbinding, expressions, and toplevel.
|
||||||
* _Simple_ expressions include all literals as well as bare names and synthetic expressions. They may go anywhere you expect an expression, e.g. in the condition position in if or when forms. But in these positions, you may not use, say, another conditional form, nor bind a name.
|
* _Simple_ expressions include all literals as well as bare names, synthetic expressions, anonymous `fn` lambdas, `do` forms, and `panic`s. They may go anywhere you expect an expression, e.g. in the condition position in if or when forms. But in these positions, you may not use, say, another conditional form, nor bind a name.
|
||||||
* _Nonbinding_ forms include all expressions _except_ those that bind a name. These include all simple expressions, as well as conditional expressions (`if`, `when`, `match`), anonymous lambdas, and `do` pipelines.
|
* _Nonbinding_ forms include all expressions _except_ those that bind a name. To simple expressions, nonbinding expressions extend to conditional forms (`if`, `when`, `match`, `receive`).
|
||||||
* _Expressions_ (tout court) include all Ludus expressions, including those that bind names: `let`, named `fn`s, and `box`.
|
* _Expressions_ (tout court) include all Ludus expressions, including those that bind names: `let`, named `fn`s, and `box`.
|
||||||
* _Toplevel_ expressions may only go at the root scope of a script. At current, the are not yet implemented (`pkg`, `use`, `test`). These are statically checked.
|
|
||||||
|
|
||||||
### Ludus has carefully managed state
|
### Ludus has carefully managed state
|
||||||
At some point, you need state.
|
At some point, you need state.
|
||||||
|
@ -450,6 +458,8 @@ fn fact (n) -> {
|
||||||
Let me tell you, this is _wild_ Ludus.
|
Let me tell you, this is _wild_ Ludus.
|
||||||
The `loop` there is very weird indeed.
|
The `loop` there is very weird indeed.
|
||||||
|
|
||||||
|
`box`es, also, are much, much slower than variables.
|
||||||
|
|
||||||
The short version is, if you can possibly avoid it--and you probably can--don't use boxes.
|
The short version is, if you can possibly avoid it--and you probably can--don't use boxes.
|
||||||
|
|
||||||
The more complex version is this:
|
The more complex version is this:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user