diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-06-03 10:50:20 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2025-03-02 14:24:49 +0000 |
| commit | 2a7d979226e98617623b550f207cec0e113ff04d (patch) | |
| tree | 0e9f2d2c36897af3a2569f287296928ba3bb9cf3 /docs/reference | |
| parent | add loop/recur (diff) | |
| download | alive-2a7d979226e98617623b550f207cec0e113ff04d.tar.gz alive-2a7d979226e98617623b550f207cec0e113ff04d.zip | |
split guide into guide and reference
Diffstat (limited to 'docs/reference')
| -rw-r--r-- | docs/reference/02_evaltime-and-runtime.md | 45 | ||||
| -rw-r--r-- | docs/reference/03-1_symbol-resolution.md | 82 | ||||
| -rw-r--r-- | docs/reference/03-3_functions.md | 54 | ||||
| -rw-r--r-- | docs/reference/index.md | 26 |
4 files changed, 207 insertions, 0 deletions
diff --git a/docs/reference/02_evaltime-and-runtime.md b/docs/reference/02_evaltime-and-runtime.md new file mode 100644 index 0000000..e718cf3 --- /dev/null +++ b/docs/reference/02_evaltime-and-runtime.md @@ -0,0 +1,45 @@ +So far, `alv` may seem a lot like any other programming language - you write +some code, save the file, and it runs, printing some output. "What about the +'continuously running' aspect from the introduction?", you may ask yourself. + +So far, we have only seen *evaltime* execution in alv - but there is also +*runtime* behavior. At *evaltime*, that is whenever there is change to the +source code, `alv` behaves similar to a Lisp. This is the part we have seen +so far. But once one such *eval cycle* has executed, *runtime* starts, and +`alv` behaves like a dataflow system like [PureData][pd], [Max/MSP][max] or +[vvvv][vvvv]. + +What looked so far like static constants are actually *streams* of values. +Whenever an input to an operator changes, the operator (may) update and respond +with a change to its output as well. To see this in action, we need to start +with a changing value. Number literals like `1` and `2`, which we used so far, +are *evaltime constant*, which means simply that they will never update. Since +all inputs to our [math/+][] operator are *evaltime constant*, the result is +constant as well. To get some *runtime* activity, we have to introduce a +side-effect input from somewhere outside the system. + +The [time/][] module contains a number of operators whose outputs update +over time. Lets take a look at [time/tick][]: + + (import* time) + (trace (tick 1)) + +This will print a series of numbers, incrementing by 1 every second. The +parameter to [time/tick][] controls how quickly it counts - try changing it to +`0.5` or `2`. As you can see, we can change [time/tick][] *while it is +running*, but it doesn't lose track of where it was! + +All of the other things we learned above apply to streams of values as well - +we can use [def][] to store them in the scope, transform them using the ops +from the [math/][] module and so on: + + (import* time math) + (def tik (tick 0.25)) + (trace (/ tik 4)) + +Note that if you leave the [time/tick][]'s *tag* in place when you move it into +the [def][] expression, it will keep on running steadily even then. + +[pd]: http://puredata.info/ +[max]: https://cycling74.com/products/max +[vvvv]: https://vvvv.org/ diff --git a/docs/reference/03-1_symbol-resolution.md b/docs/reference/03-1_symbol-resolution.md new file mode 100644 index 0000000..87568ef --- /dev/null +++ b/docs/reference/03-1_symbol-resolution.md @@ -0,0 +1,82 @@ +Both [import][] and [import*][] are actually shorthands and what they +accomplish can be done using the lower-level builtins [def][], [use][] and +[require][]. Here is how you could replace [import][]: + + #(with import:) + (import math) + (trace (math/+ 1 2)) + + #(with def and require:) + (def math (require "math")) + (trace (math/+ 1 2)) + +[require][] returns a *scope*, which is defined as the symbol `math`. +Then `math/+` is resolved by looking for `+` in this nested scope. Note that +the symbol that the scope is defined as and the name of the module that is +loaded do not have to be the same, you could call the alias whatever you want: + + #(this not possible with import!) + (def fancy-math (require "math")) + (trace (fancy-math/+ 1 2)) + +Most of the time the name of the module makes a handy prefix already, so +[import][] can be used to save a bit of typing and make the code look a bit +cleaner. [import*][], on the other hand, defines every symbol from the imported +module individually. It could be implemented with [use][] like this: + + (use (require "math")) + (trace (+ 1 2)) + +[use][] copies all symbol definitions from the scope it is passed to the +current scope. + +Note that [import][], [import*][], [def][], and [use][] all can take multiple +arguments: + + #(using the shorthands:) + (import* math logic) + (import midi osc) + + #(using require, use and def:) + (use (require "math") (require "logic")) + (def midi (require "midi") + osc (require "osc")) + +It is common to have an [import][] and [import*][] expression at the top of an +`alv` program to load all of the modules that will be used later, but the +modules don't necessarily have to be loaded at the very beginning, as long as +all symbols are defined before they are being used. + +## nested scopes +Once a symbol is defined, it cannot be changed or removed: + + (def a 3) + (def a 4) #(error!) + +It is, however, possible to 'shadow' a symbol by re-defining it in a nested +scope: So far, all symbols we have defined - using `def`, [import][] and +[import*][] - have been defined in the *global scope*, the scope that is active +in the whole `alv` program. The [do][] builtin can be used to create a new +scope and evaluate some expressions in it: + + (import string) + + (def a 1 + b 2) + + (trace (.. "first: " a " " b)) + (do + (def a 3) + (trace (.. "second: " a " " b)) + (trace (.. "third: " a " " b)) + +This example prints the following: + + trace (.. "first: " a " " b): <Value str: first: 1 2> + trace (.. "second: " a " " b): <Value str: second: 3 2> + trace (.. "third: " a " " b): <Value str: third: 1 2> + +As you can see, within a nested scope it is possible to overwrite a definition +from the parent scope. Symbols that are not explicitly redefined in a nested +scope keep their values, and changes in the nested scope do not impact the +parent scope. diff --git a/docs/reference/03-3_functions.md b/docs/reference/03-3_functions.md new file mode 100644 index 0000000..917b8d4 --- /dev/null +++ b/docs/reference/03-3_functions.md @@ -0,0 +1,54 @@ +Another builtin that creates a nested scope is [fn][], which is used to +create a *user-defined function*, which can be used to simplify repetitive +code, amongst other things: + + (import* math) + + (def add-and-trace + (fn + (a b) + (trace (+ a b)))) + + (add-and-trace 1 2) + (add-and-trace 3 4) + +Here a *function* `add-and-trace` is defined. When defining a function, first +the names of the parameters have to be given. The function defined here takes +two parameters, `a` and `b`. The last part of the function definition is called +the *function body*. + +A function created using [fn][] can be called just like an operator. When a +function is called, the parameters to the function are defined with the names +given in the definition, and then the function body is executed. The previous +example is equivalent to the following: + + (import* math) + + (def add-and-trace + (fn + (a b) + (trace (+ a b))) + + (do + (let a 1 + b 2) + (trace (+ a b))) + + (do + (let a 3 + b 4) + (trace (+ a b))) + +and the output of both is: + + trace (+ a b): <num= 3> + trace (+ a b): <num= 7> + +In `alv`, functions are first-class values and can be passed around just like +numbers, strings, etc. However it is very common to define a function with a +name, so there is the `defn` shorthand, which combines the `def` and `fn` +builtins into a single expression. Compare this equivalent definition of the +`add-and-trace` function: + + (defn add-and-trace (a b) + (trace (+ a b))) diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 0000000..cfa8fdc --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,26 @@ +__This section is currently under construction.__ + +This reference manual documents the `alv` langauge and its standard facilities +in detail. If you are new to alive, the [getting started guide][guide] is the +recommended place to start. If you are looking for information on adding your +own module or contributing to alive, check out the +[developer documentation](../internals/index.html). + +[guide]: (../guide/index.html) + +## contents + +1. syntax +2. [evaltime and runtime](02_evaltime-and-runtime.html) +3. evaltime + 1. [symbol resolution](03-1_symbol-resolution.html) + 2. if and switch + 3. [functions](03-3_functions.html) + 4. dynamic symbols + 5. loops + 6. modules and loading +4. runtime + 1. result kinds + 2. pure operators +5. [builtin listing](builtins.html) +6. included modules |
