git.s-ol.nu alive / 4b8a0f0
split guide into guide and reference s-ol 1 year, 7 months ago
32 changed file(s) with 696 addition(s) and 646 deletion(s). Raw diff Collapse all Expand all
0 MODULES=$(wildcard alv-lib/*.moon) alv-lib/midi/launchctl.moon
1 MODREFS=$(MODULES:alv-lib/%.moon=docs/reference/%.html)
0 MODULES:=$(wildcard alv-lib/*.moon) alv-lib/midi/launchctl.moon
1 MODULES:=$(MODULES:alv-lib/%.moon=docs/reference/module/%.html)
2 REFERENCE=docs/reference/index.md $(wildcard docs/reference/[01]*.md) docs/reference/builtins.html $(MODULES)
3 REFTOC=$(REFERENCE:%.md=%.html)
4
5 GUIDE=docs/guide/index.md $(wildcard docs/guide/[01]*.md)
6 GUIDETOC=$(GUIDE:%.md=%.html)
7
28 CORE=$(wildcard alv/*.moon alv/**/*.moon) $(wildcard alv/*.md)
39 DEPS=alv/version.moon $(wildcard docs/gen/*.moon)
10 GEN=docs/gen/
411
5 .PHONY: docs test release clean reference internals
12 .PHONY: docs test release clean guide reference internals
613
7 GUIDE = getting-started-guide installation hello-world syntax
8 GUIDE += working-with-the-copilot basic-types importing-operators defining-symbols
9 GUIDE += scopes functions evaltime-and-runtime making-sound
10 GUIDE := $(addprefix docs/guide/,$(addsuffix .md,$(GUIDE)))
11 docs: docs/index.html $(GUIDE:%.md=%.html) reference internals
14 docs: docs/index.html guide reference internals
1215
1316 test:
1417 busted
1518
1619 # docs parts
17 reference: $(MODREFS) docs/reference/index.html
20 guide: $(GUIDETOC)
21 reference: $(REFTOC)
1822 internals: docs/internals/index.html
1923
20 docs/guide/%.html: docs/guide/%.md $(DEPS) $(GUIDE)
24 docs/guide/%.html: docs/guide/%.md $(GUIDE) $(DEPS) $(GEN)md
2125 @echo "building page $<"
22 docs/gen/md $@ $< $(GUIDE:%.md=%.html)
26 docs/gen/md $@ $< $(GUIDETOC)
2327
24 docs/%.html: docs/%.md $(DEPS)
28 docs/reference/module/%.html: alv-lib/%.moon $(DEPS) $(GEN)module
29 @echo "building docs for $<"
30 @mkdir -p `dirname $@`
31 docs/gen/module $@ alv-lib.$(subst /,.,$*) $(subst /,.,$*) $(REFTOC)
32
33 docs/reference/builtins.html: alv/builtins.moon $(DEPS) $(GEN)module
34 @echo "building docs for $<"
35 docs/gen/module $@ alv.builtins "builtins" $(REFTOC)
36
37 docs/reference/index.html: docs/reference/index.md alv/builtins.moon $(MODULES) $(DEPS) $(GEN)index
38 @echo "building reference index"
39 docs/gen/index $@ $< $(REFTOC)
40
41 docs/reference/%.html: docs/reference/%.md $(REFERENCE) $(DEPS) $(GEN)md
42 @echo "building page $<"
43 docs/gen/md $@ $< $(REFTOC)
44
45 docs/%.html: docs/%.md $(DEPS) $(GEN)md
2546 @echo "building page $<"
2647 docs/gen/md $@ $<
27
28 docs/reference/%.html: alv-lib/%.moon $(DEPS)
29 @echo "building docs for $<"
30 @mkdir -p `dirname $@`
31 docs/gen/module $@ alv-lib.$(subst /,.,$*) $(subst /,.,$*)
32
33 docs/reference/index.html: alv/builtins.moon $(MODREFS) $(DEPS)
34 docs/gen/index $@ $(MODULES)
3548
3649 docs/ldoc.ltp: $(DEPS)
3750 docs/gen/ldoc $@
4053 ldoc alv
4154
4255 clean:
43 rm -rf docs/reference
56 rm -rf docs/reference/*.html docs/reference/modules
4457 rm -rf docs/internals/*/ docs/internals/*.css docs/internals/*.html
45 rm -f docs/index.html $(GUIDE:%.md=%.html) docs/ldoc.*
58 rm -f docs/index.html $(GUIDETOC) docs/ldoc.*
00 *.html
11 ldoc.*
22 internals/*.css
3 reference
00 #!/usr/bin/env moon
11 require 'alv'
2 import render, layout, autoref from require 'docs.gen.layout'
2 import render, layout, autoref, subnav from require 'docs.gen.layout'
33 import section, h1, h2, p, ul, li, a, code from require 'docs.gen.dom'
4 import opairs from require 'alv.util'
4 import compile from require 'discount'
55
66 export OUT
77
1515 file\write str
1616 file\close!
1717
18 { OUT } = arg
18 { OUT, file } = arg
1919
20 md = slurp file
21 for file in *arg[3,]
22 if mod = file\match '/module/(.*)%.html'
23 name = mod\gsub '/', '.'
24 md ..= " - [`#{name}`](module/#{mod}.html)\n"
25
26 content = compile (autoref md), 'githubtags', 'fencedcode'
27 sub = subnav [a for a in *arg[3,]]
2028 spit OUT, layout
21 title: 'reference'
22 body: {
23 h1 (code 'alive'), " language reference"
24 p "This section documents all builtins and modules that are currently
25 available in the alive programming language."
26 p autoref "If you are new to alive, the [getting started guide][:../guide/:] is
27 the recommended place to start. If you are looking for
28 information on adding your own module or contributing to alive, check
29 out the [developer documentation][:../internals/index/:]."
30 section {
31 id: 'modules'
32 h2 a "module index", href: '#modules'
33 p autoref "These modules can be imported using [require][], " ..
34 "[import][] and [import*][]."
35 ul for file in *arg[2,]
36 path = file\match '^alv%-lib/(.*)%.moon$'
37 name = path\gsub '/', '.'
38 li a (code name), href: "#{path}.html"
39 }
40 section {
41 id: 'builtins'
42 h2 a "builtins", href: '#builtins'
43 p "These definitions are automatically loaded into the global Scope of
44 every alive session."
45 ul for key, val in opairs (require 'alv.builtins').values
46 li render key, val.result
47 }
48 }
29 body: table.concat { sub, content.body }, '\n\n'
6666 return version.release if ref == '*release*'
6767
6868 mod, sym = ref\match '^(.+)/(.*)$'
69 abs "reference/#{mod or 'index'}.html##{sym or ref}"
69 if mod
70 abs "reference/module/#{mod}.html##{sym or ref}"
71 else
72 abs "reference/builtins.html##{sym or ref}"
7073
7174 -- link to a reference
7275 r = (text, ref) ->
8790
8891 subnav = do
8992 split_name = (file) ->
90 href, label = file\match '^docs/(.*/([%w%-]+)%.html)'
93 if href = file\match '^docs/(.*/index.html)$'
94 return 'index', href
95
96 href, label = file\match '^docs/(.*/([%d%w-_]+)%.html)$'
97 label = (label\match '^[%d-]+_([%w-]+)$') or label
9198 label = label\gsub '-', ' '
9299 label, href
100
101 title = (file) ->
102 if file == 'docs/guide/index.html'
103 return "getting started guide"
104 if file == 'docs/reference/index.html'
105 return "<code>alv</code> language reference"
106 elseif mod = file\match '^docs/reference/module/(.*)%.html$'
107 return "<code>#{mod}</code> module reference"
108 elseif href = file\match '^docs/(.*/index.html)$'
109 error "index page without hardcoded name: #{href}"
110
111 num, label = file\match '/([%d-]+)_([%w%-]+)%.html$'
112 if num
113 num = num\gsub '%f[%d]0', ''
114 num = num\gsub '-', '.'
115 label = label\gsub '-', ' '
116 "#{num}. #{label}"
117 else
118 (file\match '/([%w%-]+)%.html$')
93119
94120 subnav_link = (dir, file) ->
95121 import span, a, u from dom
118144
119145 div {
120146 class: 'subheader'
121 h1 (split_name OUT)
147 h1 (title OUT)
122148 nav {
123149 subnav_link 'l', all[c-1]
124150 subnav_link 'r', all[c+1]
128154 aopts = (href, pat) ->
129155 {
130156 href: abs href
131 class: if OUT\match "^docs/#{pat}" then 'active'
157 class: if OUT\match pat then 'active'
132158 }
133159
134160 -- layout and write a doc page
148174 ' documentation'
149175 }
150176 div class: 'grow'
151 a 'home', aopts 'index.html', 'index.html$'
152 a 'guide', aopts 'guide/getting-started-guide.html', 'guide'
153 a 'reference', aopts 'reference/index.html', 'reference'
154 a 'internals', aopts 'internals/index.html', 'ldoc'
177 a 'home', aopts 'index.html', '^docs/index.html$'
178 a 'guide', aopts 'guide/index.html', '^docs/guide'
179 a 'reference', aopts 'reference/index.html', '^docs/reference'
180 a 'internals', aopts 'internals/index.html', '^docs/ldoc'
155181 }
156182 body = article opts.body
157183 title = if opts.title
00 #!/usr/bin/env moon
1 import Scope from require 'alv'
2 import render, layout from require 'docs.gen.layout'
3 import section, h2, h3, ul, li, code from require 'docs.gen.dom'
1 import Constant from require 'alv'
2 import render, layout, subnav from require 'docs.gen.layout'
3 import h2, h3, ul, li, code from require 'docs.gen.dom'
44 import opairs from require 'alv.util'
55
66 export OUT, require
2525 { OUT, module, name } = arg
2626
2727 name or= module
28 module = Scope.from_table require module
28 const = Constant.wrap require module
29 module = const\unwrap!
2930
3031 spit OUT, layout
31 title: "#{name} reference"
32 body: section {
32 title: "#{name} module reference"
33 body: table.concat {
34 subnav [a for a in *arg[4,]]
3335 h2 (code name), ' module reference'
3436 h3 'index'
3537 ul for key, node in opairs module.values
3739 h3 'details'
3840 ul for key, node in opairs module.values
3941 li render key, node.result
40 }
42 }, ''
0 `alv` is written in the Lua programming language, and is compatible with both
1 Lua 5.3 and luajit.
2
3 ## unix/linux and mac os
4 Your distribution should provide you with packages for Lua and Luarocks. On Mac
5 OS X, both are provided through [homebrew][homebrew]. After installing both of
6 these, you should be able to start the Lua interpreter from the shell:
7
8 $ lua
9 Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
10 >
11
12 You can exit using `CTRL+C`. If the version you see is not 5.3, double check
13 your distribution packages or see if it was installed as `lua5.3` or `lua53`.
14 Similarily, you should be able to run `luarocks`, `luarocks53` or `luarocks5.3`:
15
16 $ luarocks list
17
18 Rocks installed for Lua 5.3
19 ---------------------------
20
21 Again, double check your installation or try adding `--lua-version 5.3` if the
22 displayed version is not 5.3.
23
24 With everything ready to go, you can now install `alv`:
25
26 $ luarocks install alive
27
28 To use the copilot GUI, you will also need the `fltk4lua` package, which requires
29 installing or building FLTK (also available through homebrew).
30
31 $ luarocks install fltk4lua
32
33 With the `alive` package, two binaries should have been installed on your system:
34 `alv` and `alv-fltk`. If you do not find these in your `$PATH`, you may need to
35 apply the exports from `luarocks path` upon login, e.g. in your `.bashrc`.
36
37 ## windows
38 For Windows, a binary package is available from the latest
39 [github release][:*release*:]. It includes not only the `alv` source code, but
40 also a compiled version of Lua 5.3 as well as Luarocks and all of `alv`'s
41 dependencies.
42
43 To use the binary package, simply extract the archive and move the folder
44 wherever you want. You can now start the `hello.alv` example script by dragging
45 it onto the `alv.bat` or `alv-fltk.bat` file in the folder.
46
47 If you are going to use the command-line `alv.bat`, it is recommended to add
48 the directory containing it to `%PATH%`, so that you can use the `alv` command
49 anywhere on your system.
50
51 [homebrew]: https://brew.sh
52 [luarocks]: https://github.com/luarocks/luarocks/#installing
0 Before getting into all the details of the `alv` language, let's quickly run an
1 example program to make sure that everything is working correctly:
2
3 ([1]import* time)
4 ([2]print ([3]every 0.5 "hello world!"))
5
6 Open a text file save this piece of code as `hello.alv`. You can also find this
7 example program in the repository and the windows binary package.
8
9 As mentioned earlier, there are two different ways to run `alv` programs: using
10 the copilot GUI, or in the terminal.
11
12 ## starting the copilot GUI
13 On Linux and Mac OS X, you can launch the GUI by executing the `alv-fltk`
14 command. On Windows, you can double-click `alv-fltk.bat`. This window should
15 open:
16
17 ![a screeshot of the copilot GUI](copilot-gui.png)
18
19 Now open `hello.alv` using `File > Open Script` or the shortcut `^O`
20 (control-O). The copilot should start printing `hello world` over and over
21 again in the lower field.
22
23 You can pause and resume execution using the `Run` button or the `^P` shortcut.
24 To stop the program simply close the window.
25
26 ## starting the copilot in the terminal
27 To run a file in the terminal, invoke the command `alv <path/to/hello.alv>`. If
28 your system cannot find the `alv` command, check your installation and `PATH`.
29 On Windows, it is also possible to drag your `alv` file onto `alv.bat`.
30
31 You should now see the text `hello world` being printed over and over again,
32 twice a second. You can stop the copilot by pressing `^C` (control-C).
0 While it is possible to simply run finished programs as we just did with the
1 `hello.alv` example, `alv` is a *livecoding language*, which means that it is
2 designed so that programs can be written interactively while they are already
3 running. To see how this works, let's re-write the `hello.alv` example
4 step-by-step.
5
6 First you will need an empty file to start from. Open a new file in your
7 preferred text editor and save it as `test.alv`. Before adding any code, start
8 the copilot (see the last page on the two ways of doing that).
9
10 $ alv test.alv
11 changes to files: test.alv
12
13 You should see a note indicating that `alv` processed the file. The note will
14 show up in the upper pane labelled `eval` (in the GUI), or colored green (in
15 the terminal). This marks the message as an *eval-time message*, meaning that
16 the message was printed as a direct response to the file changing or being
17 loaded the first time. Other messages that might print to the `eval` section
18 are things like errors in your program, and one-time debugging messages.
19
20 Now that the copilot is running, whenever you change `test.alv` and save it, the
21 copilot will reload it and execute your new code. When you are done, you can
22 stop the copilot at any time by closing the GUI window or pressing `^C`
23 (control-C) in the terminal.
24
25 Let's start with a simple operator, [print][]: [print][] is used simply to print
26 messages to the copilot console. Enter the following in your file and save it:
27
28 (print "hello world!")
29
30 As soon as you save the file, you should notice two things happening:
31
32 1. The copilot will print two new lines:
33
34 changes to files: hello.alv
35 hello world!
36
37 In the first line, it notifies us that the file has changed. In the second
38 line, you can see the output from the [print][] expression.
39 2. The copilot will make a small modification to your file. Depending on the
40 editor you are using, this may either result in you seeing the modification
41 immediately, or a notice appearing that offers the option to reload the
42 file. If it is the latter, confirm the notification to accept the changes.
43 If there is an option to do so, you may want to configure your editor to
44 always reload the file automatically.
45
46 The code should now look like this:
47
48 ([1]print "hello world")
49
50 The `[1]` that the copilot added to your expression is that expression's `tag`.
51 In `alv`, every expression has a tag that helps the copilot to identify the
52 individual expressions as you make changes to your code. The copilot will make
53 sure that all expressions are tagged by adding missing tags when you save the
54 file, but you have to watch out not to duplicate a tag when copying and pasting
55 code. When you duplicate code that already has tags, you can either manually
56 change the tags to be unique, or simply delete the whole tag (including the
57 square brackets) and let the copilot generate a new one for you the next time
58 you save the file.
0 `alv`'s syntax is very similar to Lisp. Expressions take the form of
1 parenthesized lists like `(head a b c...)`, where the first element of the list
2 (`head`) is the name of an operator or function, which defines what the
3 expression as a whole will do, while the other elements are parameters whose
4 meaning depends on the `head`. Let's start with a simple operator, [print][]:
5 [print][] is used simply to print messages to the copilot console.
6
7 ## expressions
8 Elements of an expression have to be separated by whitespace, but any type of
9 and amount of whitespace is valid: feel free to use spaces, tabs, and newlines
10 to format code to your liking. The following are all equal and valid examples:
11
12 (print "hello world")
13
14 (+ 1
15 2
16 3)
17
18 (print
19 "hello world")
20
21 ( print "hello world" )
22
23 It is however recommended to follow the [clojure style guide][clojure-style] as
24 much as it does apply to alv. All further examples in this guide will respect
25 this guideline, so you might just pick it up simply by following this guide.
26
27 ## comments
28 To annotate your code, you can use comments. In `alv`, comments begin with
29 `#(` and end on a matching `)`. This way you can comment out a complete
30 expression simply by adding a `#` character in front.
31
32 #(this is a comment)
33
34 #(this is a long,
35 multi-line comment,
36 (and it also has nested parentheses).
37 It ends after this sentence.)
38
39 You can put comments anywhere in your program where whitespace is allowed and
40 it will simply be ignored by `alv`.
41
42 [clojure-style]: https://github.com/bbatsov/clojure-style-guide
0 Strings can be written in two ways: using double quotes (`"`), as we did above,
1 or using single quotes (`'`). In both types of strings, you can escape a quote
2 that otherwise would signify the end of the string by adding a single backslash
3 before it. Consequently, backslashes also have to be escaped in the same way.
4 The following are all valid strings:
5
6 "hello world"
7 'hello world'
8 "it's a beautiful day"
9 'it\'s a beautiful day'
10 "this is a backslash: \\"
11 "this is a double quote: \""
12 ""
13 ''
14
15 Aside from strings, there are two more types of values that you can use when
16 writing alv programs: numbers and booleans. Numbers use the digits 0-9 and
17 can be integers, contain a decimal point, or start or end with a decimal point.
18 Numbers can start with a negetive sign. The following are all valid numbers:
19
20 0
21 12
22 -7
23 0.1
24 10.
25 .1
26 123.
27
28 There are only two boolean values, `true` and `false`:
29
30 true
31 false
32
33 The operator [print][], that we have been using above, only works on strings,
34 but there is a similar operator called [trace][] that can be used to inspect
35 any kind of value. It prints the value itself alongside more information, such
36 as the values type. Give it a try:
37
38 (trace "hello")
39 (trace 2)
40 (trace true)
41
42 This will print the following:
43
44 changes to files: values.alv
45 trace "hello": <str= "hello">
46 trace 2: <num= 2>
47 trace true: <bool= true>
48
49 On the left side of the colon, [trace][] prints the expression that it is
50 evaluating. On the right side, three pieces of information are shown:
51
52 - the *type*: `str`, `num`, `bool`
53 - the *value* itself: `"hello"`, `2`, `true`
54 - the *kind* of the result: `=`
55
56 `=` means that these values are *constant* - they will not change by themselves
57 until the code is changed. For simple values like these that seems obvious, but
58 in `alv` we can also create values tha change over time, as we will see soon.
0 Apart from [trace][], there are only very little builtin operators in `alv` -
1 you can see all of them in the *builtins* section of the [reference][:/:].
2 All of the 'real' functionality of `alv` is grouped into *modules*, that have
3 to be loaded individually. *Modules* help organize all of the operators so that
4 it is less overwhelming to look for a concrete feature. It is also possible to
5 create your own plugins as new modules, which will be covered in another guide
6 soon.
7
8 Let's try using the [`+` operator][:math/+:] from the [math/][] module. To use
9 operators from a module, we need to tell `alv` to load it first: We can load
10 *all* the operators from the [math/][] module into the current scope using the
11 [import*][] builtin:
12
13 (import* math)
14 (trace (+ 1 2))
15
16 prints
17
18 trace (+ 1 2): <num= 3>
19
20 Because it can get a bit confusing when all imported operators are mixed in the
21 global scope, it is also possible to load the module into its own scope and use
22 it with a prefix. This is what the [import][] builtin is for:
23
24 (import math)
25 (trace (math/+ 1 2))
0 Another element of code in `alv` that we haven't discussed in detail yet are
1 *symbols*. *Symbols* (like `trace`, `import*` or `math/+`) are names that serve
2 as placeholders for previously *defined* values. When code is evaluated, symbols
3 are looked up in the current *scope* and replaced with the corresponding value
4 found there.
5
6 When an `alv` file starts running, a number of symbols are defined in the
7 default scope: These are the *builtins* mentioned above, and of which we have
8 already been using [trace][], [import][], and [import*][].
9
10 To *define a symbol* yourself, the [def][] builtin is used. It takes the symbol
11 as its first, and the value to associate as its second parameter. After a symbol
12 is defined, the name becomes an alias that behaves like the value itself. For
13 example, we can use [def][] to associate the result of our calculation with the
14 symbol `result`, and then refer to it by that symbol in the [trace][] operator:
15
16 (import* math)
17
18 (def result (+ 1 2))
19 (trace result)
20
21 Symbols need to start with a letter or one of the characters `-_+*/.=~!?%`.
22 After the first character, numbers are also allowed. There are two types of
23 symbols that are treated specially: symbols containing a slash (`math/+`), and
24 symbols starting and ending with asterisks (`*clock*`):
25
26 - Symbols containing slashes (except at beginning and end of the symbol) are
27 split into multiple symbols, and looked up recursively in the scope. For
28 example, `math/+` is found by first looking for a value for the symbol `math`,
29 and then looking for the symbol `+` in that value. If the value for the
30 symbol `math` is not a scope, an error is thrown.
31 - Symbols starting and ending with asterisks are called `dynamic symbols` and
32 are looked up in a different way inside user-defined functions. This will be
33 covered in detail later.
34 - The two special formats can be mixed: when evaluating `*hello*/world`,
35 `alv` will look for the symbol `world` within the scope found by dynamically
36 resolving `*hello*`.
0 As mentioned earlier, `alv` doesn't produce sound by itself. Instead, it is
1 paired with other tools, and takes the role of a 'Conductor', sending commands
2 and sequencing other tools.
3
4 For the sake of this guide, we will be controlling [Pilot][pilot], a simple
5 UDP-controlled synthesizer. You can go ahead and download and open it now.
6 You should see a small window with a bunch of cryptic symbols and a little
7 command line at the bottom. To verify that everything is working so far,
8 try typing in `84c` and hitting enter. This should play a short sound (the note
9 4C, played by the 8th default synthesizer voice in Pilot).
10
11 To talk to Pilot from `alv`, we will use the [pilot/][] module. Note that for
12 this module to work, you have to have the `osc` and `luasocket` dependencies
13 installed. To play the same sound we played by entering `84c` above every 0.5
14 seconds, we can use [time/every][] to send a `bang` to [pilot/play][]:
15
16 (import* time)
17 (import pilot)
18 (pilot/play (every 0.5) 8 4 'c')
19
20 You can play with the voice, octave and note values a bit. To add a simple
21 melody, we can use [util/switch][], which will cycle through a list of
22 parameters when used together with [time/tick][]:
23
24 (import* time util)
25 (import pilot)
26 (pilot/play (every 0.5) 8 4
27 (switch (tick 0.5) 'c' 'd' 'a' 'f'))
28
29 Now we can have the voice change every other loop as well:
30
31 (import* time util)
32 (import pilot)
33 (pilot/play (every 0.5)
34 (switch (tick 4) 8 9)
35 4 (switch (tick 0.5) 'c' 'd' 'a' 'f'))
36
37 To round off the sound a bit, we can turn on Pilot's reverb using
38 [pilot/effect][]. Add the following somewhere in your file:
39
40 (pilot/effect "REV" 2 8)
41
42 Now it's time to add some rhythm. The kick drum is voice 12 by default,
43 and we can also add something like a snare on channel 3:
44
45 (pilot/play (every 0.75)
46 12 2 'd' 3)
47 (pilot/play (every 2)
48 13 4 'a' 4)
49
50 Note that since we are using multiple individual [time/every][] instances,
51 the timing of our voices relative to each other is not aligned - each voice
52 started playing when the file was first saved with it added, and kept the
53 rhythmn since. By deleting all their tags and re-saving the file, we can force
54 `alv` to re-instantiate them all at the same time, thereby synchronising
55 them.
56
57 [pilot]: https://github.com/hundredrabbits/Pilot
+0
-59
docs/guide/basic-types.md less more
0 Strings can be written in two ways: using double quotes (`"`), as we did above,
1 or using single quotes (`'`). In both types of strings, you can escape a quote
2 that otherwise would signify the end of the string by adding a single backslash
3 before it. Consequently, backslashes also have to be escaped in the same way.
4 The following are all valid strings:
5
6 "hello world"
7 'hello world'
8 "it's a beautiful day"
9 'it\'s a beautiful day'
10 "this is a backslash: \\"
11 "this is a double quote: \""
12 ""
13 ''
14
15 Aside from strings, there are two more types of values that you can use when
16 writing alv programs: numbers and booleans. Numbers use the digits 0-9 and
17 can be integers, contain a decimal point, or start or end with a decimal point.
18 Numbers can start with a negetive sign. The following are all valid numbers:
19
20 0
21 12
22 -7
23 0.1
24 10.
25 .1
26 123.
27
28 There are only two boolean values, `true` and `false`:
29
30 true
31 false
32
33 The operator [print][], that we have been using above, only works on strings,
34 but there is a similar operator called [trace][] that can be used to inspect
35 any kind of value. It prints the value itself alongside more information, such
36 as the values type. Give it a try:
37
38 (trace "hello")
39 (trace 2)
40 (trace true)
41
42 This will print the following:
43
44 changes to files: values.alv
45 trace "hello": <str= "hello">
46 trace 2: <num= 2>
47 trace true: <bool= true>
48
49 On the left side of the colon, [trace][] prints the expression that it is
50 evaluating. On the right side, three pieces of information are shown:
51
52 - the *type*: `str`, `num`, `bool`
53 - the *value* itself: `"hello"`, `2`, `true`
54 - the *kind* of the result: `=`
55
56 `=` means that these values are *constant* - they will not change by themselves
57 until the code is changed. For simple values like these that seems obvious, but
58 in `alv` we can also create values tha change over time, as we will see soon.
+0
-37
docs/guide/defining-symbols.md less more
0 Another element of code in `alv` that we haven't discussed in detail yet are
1 *symbols*. *Symbols* (like `trace`, `import*` or `math/+`) are names that serve
2 as placeholders for previously *defined* values. When code is evaluated, symbols
3 are looked up in the current *scope* and replaced with the corresponding value
4 found there.
5
6 When an `alv` file starts running, a number of symbols are defined in the
7 default scope: These are the *builtins* mentioned above, and of which we have
8 already been using [trace][], [import][], and [import*][].
9
10 To *define a symbol* yourself, the [def][] builtin is used. It takes the symbol
11 as its first, and the value to associate as its second parameter. After a symbol
12 is defined, the name becomes an alias that behaves like the value itself. For
13 example, we can use [def][] to associate the result of our calculation with the
14 symbol `result`, and then refer to it by that symbol in the [trace][] operator:
15
16 (import* math)
17
18 (def result (+ 1 2))
19 (trace result)
20
21 Symbols need to start with a letter or one of the characters `-_+*/.=~!?%`.
22 After the first character, numbers are also allowed. There are two types of
23 symbols that are treated specially: symbols containing a slash (`math/+`), and
24 symbols starting and ending with asterisks (`*clock*`):
25
26 - Symbols containing slashes (except at beginning and end of the symbol) are
27 split into multiple symbols, and looked up recursively in the scope. For
28 example, `math/+` is found by first looking for a value for the symbol `math`,
29 and then looking for the symbol `+` in that value. If the value for the
30 symbol `math` is not a scope, an error is thrown.
31 - Symbols starting and ending with asterisks are called `dynamic symbols` and
32 are looked up in a different way inside user-defined functions. This will be
33 covered in detail later.
34 - The two special formats can be mixed: when evaluating `*hello*/world`,
35 `alv` will look for the symbol `world` within the scope found by dynamically
36 resolving `*hello*`.
+0
-45
docs/guide/evaltime-and-runtime.md less more
0 So far, `alv` may seem a lot like any other programming language - you write
1 some code, save the file, and it runs, printing some output. "What about the
2 'continuously running' aspect from the introduction?", you may ask yourself.
3
4 So far, we have only seen *evaltime* execution in alv - but there is also
5 *runtime* behavior. At *evaltime*, that is whenever there is change to the
6 source code, `alv` behaves similar to a Lisp. This is the part we have seen
7 so far. But once one such *eval cycle* has executed, *runtime* starts, and
8 `alv` behaves like a dataflow system like [PureData][pd], [Max/MSP][max] or
9 [vvvv][vvvv].
10
11 What looked so far like static constants are actually *streams* of values.
12 Whenever an input to an operator changes, the operator (may) update and respond
13 with a change to its output as well. To see this in action, we need to start
14 with a changing value. Number literals like `1` and `2`, which we used so far,
15 are *evaltime constant*, which means simply that they will never update. Since
16 all inputs to our [math/+][] operator are *evaltime constant*, the result is
17 constant as well. To get some *runtime* activity, we have to introduce a
18 side-effect input from somewhere outside the system.
19
20 The [time/][] module contains a number of operators whose outputs update
21 over time. Lets take a look at [time/tick][]:
22
23 (import* time)
24 (trace (tick 1))
25
26 This will print a series of numbers, incrementing by 1 every second. The
27 parameter to [time/tick][] controls how quickly it counts - try changing it to
28 `0.5` or `2`. As you can see, we can change [time/tick][] *while it is
29 running*, but it doesn't lose track of where it was!
30
31 All of the other things we learned above apply to streams of values as well -
32 we can use [def][] to store them in the scope, transform them using the ops
33 from the [math/][] module and so on:
34
35 (import* time math)
36 (def tik (tick 0.25))
37 (trace (/ tik 4))
38
39 Note that if you leave the [time/tick][]'s *tag* in place when you move it into
40 the [def][] expression, it will keep on running steadily even then.
41
42 [pd]: http://puredata.info/
43 [max]: https://cycling74.com/products/max
44 [vvvv]: https://vvvv.org/
+0
-54
docs/guide/functions.md less more
0 Another builtin that creates a nested scope is [fn][], which is used to
1 create a *user-defined function*, which can be used to simplify repetitive
2 code, amongst other things:
3
4 (import* math)
5
6 (def add-and-trace
7 (fn
8 (a b)
9 (trace (+ a b))))
10
11 (add-and-trace 1 2)
12 (add-and-trace 3 4)
13
14 Here a *function* `add-and-trace` is defined. When defining a function, first
15 the names of the parameters have to be given. The function defined here takes
16 two parameters, `a` and `b`. The last part of the function definition is called
17 the *function body*.
18
19 A function created using [fn][] can be called just like an operator. When a
20 function is called, the parameters to the function are defined with the names
21 given in the definition, and then the function body is executed. The previous
22 example is equivalent to the following:
23
24 (import* math)
25
26 (def add-and-trace
27 (fn
28 (a b)
29 (trace (+ a b)))
30
31 (do
32 (let a 1
33 b 2)
34 (trace (+ a b)))
35
36 (do
37 (let a 3
38 b 4)
39 (trace (+ a b)))
40
41 and the output of both is:
42
43 trace (+ a b): <num= 3>
44 trace (+ a b): <num= 7>
45
46 In `alv`, functions are first-class values and can be passed around just like
47 numbers, strings, etc. However it is very common to define a function with a
48 name, so there is the `defn` shorthand, which combines the `def` and `fn`
49 builtins into a single expression. Compare this equivalent definition of the
50 `add-and-trace` function:
51
52 (defn add-and-trace (a b)
53 (trace (+ a b)))
+0
-25
docs/guide/getting-started-guide.md less more
0 `alv` ("alive") is a language for creating and changing realtime programs while
1 they are running continuously. It can be used to create music, visuals or
2 installations, but by itself creates neither sound nor video. Rather, `alv` is
3 used together with other tools and synthesizers (for example
4 [SuperCollider][supercollider] or [Pilot][pilot]). In such an ensemble of
5 tools, `alive` takes the role of a 'conductor', telling the other tools what to
6 play when by sending commands to them using a variety of protocols, such as OSC
7 and MIDI.
8
9 ## contents
10
11 1. [installation](installation.html)
12 2. [hello world](hello-world.html)
13 3. [working with the copilot](working-with-the-copilot.html)
14 4. [syntax](syntax.html)
15 5. [basic types](basic-types.html)
16 6. [importing operators](importing-operators.html)
17 7. [defining symbols](symbols.html)
18 8. [scopes](scopes.html)
19 9. [functions](functions.html)
20 10. [evaltime and runtime](evaltime-and-runtime.html)
21 11. [making sound](making-sound.html)
22
23 [supercollider]: https://supercollider.github.io/
24 [pilot]: https://github.com/hundredrabbits/Pilot
+0
-33
docs/guide/hello-world.md less more
0 Before getting into all the details of the `alv` language, let's quickly run an
1 example program to make sure that everything is working correctly:
2
3 ([1]import* time)
4 ([2]print ([3]every 0.5 "hello world!"))
5
6 Open a text file save this piece of code as `hello.alv`. You can also find this
7 example program in the repository and the windows binary package.
8
9 As mentioned earlier, there are two different ways to run `alv` programs: using
10 the copilot GUI, or in the terminal.
11
12 ## starting the copilot GUI
13 On Linux and Mac OS X, you can launch the GUI by executing the `alv-fltk`
14 command. On Windows, you can double-click `alv-fltk.bat`. This window should
15 open:
16
17 ![a screeshot of the copilot GUI](copilot-gui.png)
18
19 Now open `hello.alv` using `File > Open Script` or the shortcut `^O`
20 (control-O). The copilot should start printing `hello world` over and over
21 again in the lower field.
22
23 You can pause and resume execution using the `Run` button or the `^P` shortcut.
24 To stop the program simply close the window.
25
26 ## starting the copilot in the terminal
27 To run a file in the terminal, invoke the command `alv <path/to/hello.alv>`. If
28 your system cannot find the `alv` command, check your installation and `PATH`.
29 On Windows, it is also possible to drag your `alv` file onto `alv.bat`.
30
31 You should now see the text `hello world` being printed over and over again,
32 twice a second. You can stop the copilot by pressing `^C` (control-C).
+0
-26
docs/guide/importing-operators.md less more
0 Apart from [trace][], there are only very little builtin operators in `alv` -
1 you can see all of them in the *builtins* section of the [reference][:/:].
2 All of the 'real' functionality of `alv` is grouped into *modules*, that have
3 to be loaded individually. *Modules* help organize all of the operators so that
4 it is less overwhelming to look for a concrete feature. It is also possible to
5 create your own plugins as new modules, which will be covered in another guide
6 soon.
7
8 Let's try using the [`+` operator][:math/+:] from the [math/][] module. To use
9 operators from a module, we need to tell `alv` to load it first: We can load
10 *all* the operators from the [math/][] module into the current scope using the
11 [import*][] builtin:
12
13 (import* math)
14 (trace (+ 1 2))
15
16 prints
17
18 trace (+ 1 2): <num= 3>
19
20 Because it can get a bit confusing when all imported operators are mixed in the
21 global scope, it is also possible to load the module into its own scope and use
22 it with a prefix. This is what the [import][] builtin is for:
23
24 (import math)
25 (trace (math/+ 1 2))
0 `alv` ("alive") is a language for creating and changing realtime programs while
1 they are running continuously. It can be used to create music, visuals or
2 installations, but by itself creates neither sound nor video. Rather, `alv` is
3 used together with other tools and synthesizers (for example
4 [SuperCollider][supercollider] or [Pilot][pilot]). In such an ensemble of
5 tools, `alive` takes the role of a 'conductor', telling the other tools what to
6 play when by sending commands to them using a variety of protocols, such as OSC
7 and MIDI.
8
9 This guide will get you up and running with `alv` and [Pilot][pilot], explaining
10 most of the basics along the way. For more complete documentation on the `alv`
11 language and features like functions, loops, etc. take a look at the
12 [language reference](../reference/index.html).
13
14 ## contents
15
16 1. [installation](01_installation.html)
17 2. [hello world](02_hello-world.html)
18 3. [working with the copilot](03_working-with-the-copilot.html)
19 4. [syntax](04_syntax.html)
20 5. [basic types](05_basic-types.html)
21 6. [importing operators](06_importing-operators.html)
22 7. [defining symbols](07_symbols.html)
23 8. [making sound](08_making-sound.html)
24
25 [supercollider]: https://supercollider.github.io/
26 [pilot]: https://github.com/hundredrabbits/Pilot
+0
-53
docs/guide/installation.md less more
0 `alv` is written in the Lua programming language, and is compatible with both
1 Lua 5.3 and luajit.
2
3 ## unix/linux and mac os
4 Your distribution should provide you with packages for Lua and Luarocks. On Mac
5 OS X, both are provided through [homebrew][homebrew]. After installing both of
6 these, you should be able to start the Lua interpreter from the shell:
7
8 $ lua
9 Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
10 >
11
12 You can exit using `CTRL+C`. If the version you see is not 5.3, double check
13 your distribution packages or see if it was installed as `lua5.3` or `lua53`.
14 Similarily, you should be able to run `luarocks`, `luarocks53` or `luarocks5.3`:
15
16 $ luarocks list
17
18 Rocks installed for Lua 5.3
19 ---------------------------
20
21 Again, double check your installation or try adding `--lua-version 5.3` if the
22 displayed version is not 5.3.
23
24 With everything ready to go, you can now install `alv`:
25
26 $ luarocks install alive
27
28 To use the copilot GUI, you will also need the `fltk4lua` package, which requires
29 installing or building FLTK (also available through homebrew).
30
31 $ luarocks install fltk4lua
32
33 With the `alive` package, two binaries should have been installed on your system:
34 `alv` and `alv-fltk`. If you do not find these in your `$PATH`, you may need to
35 apply the exports from `luarocks path` upon login, e.g. in your `.bashrc`.
36
37 ## windows
38 For Windows, a binary package is available from the latest
39 [github release][:*release*:]. It includes not only the `alv` source code, but
40 also a compiled version of Lua 5.3 as well as Luarocks and all of `alv`'s
41 dependencies.
42
43 To use the binary package, simply extract the archive and move the folder
44 wherever you want. You can now start the `hello.alv` example script by dragging
45 it onto the `alv.bat` or `alv-fltk.bat` file in the folder.
46
47 If you are going to use the command-line `alv.bat`, it is recommended to add
48 the directory containing it to `%PATH%`, so that you can use the `alv` command
49 anywhere on your system.
50
51 [homebrew]: https://brew.sh
52 [luarocks]: https://github.com/luarocks/luarocks/#installing
+0
-58
docs/guide/making-sound.md less more
0 As mentioned earlier, `alv` doesn't produce sound by itself. Instead, it is
1 paired with other tools, and takes the role of a 'Conductor', sending commands
2 and sequencing other tools.
3
4 For the sake of this guide, we will be controlling [Pilot][pilot], a simple
5 UDP-controlled synthesizer. You can go ahead and download and open it now.
6 You should see a small window with a bunch of cryptic symbols and a little
7 command line at the bottom. To verify that everything is working so far,
8 try typing in `84c` and hitting enter. This should play a short sound (the note
9 4C, played by the 8th default synthesizer voice in Pilot).
10
11 To talk to Pilot from `alv`, we will use the [pilot/][] module. Note that for
12 this module to work, you have to have the `osc` and `luasocket` dependencies
13 installed. To play the same sound we played by entering `84c` above every 0.5
14 seconds, we can use [time/every][] to send a `bang` to [pilot/play][]:
15
16 (import* time)
17 (import pilot)
18 (pilot/play (every 0.5) 8 4 'c')
19
20 You can play with the voice, octave and note values a bit. To add a simple
21 melody, we can use [util/switch][], which will cycle through a list of
22 parameters when used together with [time/tick][]:
23
24 (import* time util)
25 (import pilot)
26 (pilot/play (every 0.5) 8 4
27 (switch (tick 0.5) 'c' 'd' 'a' 'f'))
28
29 Now we can have the voice change every other loop as well:
30
31 (import* time util)
32 (import pilot)
33 (pilot/play (every 0.5)
34 (switch (tick 4) 8 9)
35 4 (switch (tick 0.5) 'c' 'd' 'a' 'f'))
36
37 To round off the sound a bit, we can turn on Pilot's reverb using
38 [pilot/effect][]. Add the following somewhere in your file:
39
40 (pilot/effect "REV" 2 8)
41
42 Now it's time to add some rhythm. The kick drum is voice 12 by default,
43 and we can also add something like a snare on channel 3:
44
45 (pilot/play (every 0.75)
46 12 2 'd' 3)
47 (pilot/play (every 2)
48 13 4 'a' 4)
49
50 Note that since we are using multiple individual [time/every][] instances,
51 the timing of our voices relative to each other is not aligned - each voice
52 started playing when the file was first saved with it added, and kept the
53 rhythmn since. By deleting all their tags and re-saving the file, we can force
54 `alv` to re-instantiate them all at the same time, thereby synchronising
55 them.
56
57 [pilot]: https://github.com/hundredrabbits/Pilot
+0
-82
docs/guide/scopes.md less more
0 Both [import][] and [import*][] are actually shorthands and what they
1 accomplish can be done using the lower-level builtins [def][], [use][] and
2 [require][]. Here is how you could replace [import][]:
3
4 #(with import:)
5 (import math)
6 (trace (math/+ 1 2))
7
8 #(with def and require:)
9 (def math (require "math"))
10 (trace (math/+ 1 2))
11
12 [require][] returns a *scope*, which is defined as the symbol `math`.
13 Then `math/+` is resolved by looking for `+` in this nested scope. Note that
14 the symbol that the scope is defined as and the name of the module that is
15 loaded do not have to be the same, you could call the alias whatever you want:
16
17 #(this not possible with import!)
18 (def fancy-math (require "math"))
19 (trace (fancy-math/+ 1 2))
20
21 Most of the time the name of the module makes a handy prefix already, so
22 [import][] can be used to save a bit of typing and make the code look a bit
23 cleaner. [import*][], on the other hand, defines every symbol from the imported
24 module individually. It could be implemented with [use][] like this:
25
26 (use (require "math"))
27 (trace (+ 1 2))
28
29 [use][] copies all symbol definitions from the scope it is passed to the
30 current scope.
31
32 Note that [import][], [import*][], [def][], and [use][] all can take multiple
33 arguments:
34
35 #(using the shorthands:)
36 (import* math logic)
37 (import midi osc)
38
39 #(using require, use and def:)
40 (use (require "math") (require "logic"))
41 (def midi (require "midi")
42 osc (require "osc"))
43
44 It is common to have an [import][] and [import*][] expression at the top of an
45 `alv` program to load all of the modules that will be used later, but the
46 modules don't necessarily have to be loaded at the very beginning, as long as
47 all symbols are defined before they are being used.
48
49 ## nested scopes
50 Once a symbol is defined, it cannot be changed or removed:
51
52 (def a 3)
53 (def a 4) #(error!)
54
55 It is, however, possible to 'shadow' a symbol by re-defining it in a nested
56 scope: So far, all symbols we have defined - using `def`, [import][] and
57 [import*][] - have been defined in the *global scope*, the scope that is active
58 in the whole `alv` program. The [do][] builtin can be used to create a new
59 scope and evaluate some expressions in it:
60
61 (import string)
62
63 (def a 1
64 b 2)
65
66 (trace (.. "first: " a " " b))
67 (do
68 (def a 3)
69 (trace (.. "second: " a " " b))
70 (trace (.. "third: " a " " b))
71
72 This example prints the following:
73
74 trace (.. "first: " a " " b): <Value str: first: 1 2>
75 trace (.. "second: " a " " b): <Value str: second: 3 2>
76 trace (.. "third: " a " " b): <Value str: third: 1 2>
77
78 As you can see, within a nested scope it is possible to overwrite a definition
79 from the parent scope. Symbols that are not explicitly redefined in a nested
80 scope keep their values, and changes in the nested scope do not impact the
81 parent scope.
+0
-43
docs/guide/syntax.md less more
0 `alv`'s syntax is very similar to Lisp. Expressions take the form of
1 parenthesized lists like `(head a b c...)`, where the first element of the list
2 (`head`) is the name of an operator or function, which defines what the
3 expression as a whole will do, while the other elements are parameters whose
4 meaning depends on the `head`. Let's start with a simple operator, [print][]:
5 [print][] is used simply to print messages to the copilot console.
6
7 ## expressions
8 Elements of an expression have to be separated by whitespace, but any type of
9 and amount of whitespace is valid: feel free to use spaces, tabs, and newlines
10 to format code to your liking. The following are all equal and valid examples:
11
12 (print "hello world")
13
14 (+ 1
15 2
16 3)
17
18 (print
19 "hello world")
20
21 ( print "hello world" )
22
23 It is however recommended to follow the [clojure style guide][clojure-style] as
24 much as it does apply to alv. All further examples in this guide will respect
25 this guideline, so you might just pick it up simply by following this guide.
26
27 ## comments
28 To annotate your code, you can use comments. In `alv`, comments begin with
29 `#(` and end on a matching `)`. This way you can comment out a complete
30 expression simply by adding a `#` character in front.
31
32 #(this is a comment)
33
34 #(this is a long,
35 multi-line comment,
36 (and it also has nested parentheses).
37 It ends after this sentence.)
38
39 You can put comments anywhere in your program where whitespace is allowed and
40 it will simply be ignored by `alv`.
41
42 [clojure-style]: https://github.com/bbatsov/clojure-style-guide
+0
-59
docs/guide/working-with-the-copilot.md less more
0 While it is possible to simply run finished programs as we just did with the
1 `hello.alv` example, `alv` is a *livecoding language*, which means that it is
2 designed so that programs can be written interactively while they are already
3 running. To see how this works, let's re-write the `hello.alv` example
4 step-by-step.
5
6 First you will need an empty file to start from. Open a new file in your
7 preferred text editor and save it as `test.alv`. Before adding any code, start
8 the copilot (see the last page on the two ways of doing that).
9
10 $ alv test.alv
11 changes to files: test.alv
12
13 You should see a note indicating that `alv` processed the file. The note will
14 show up in the upper pane labelled `eval` (in the GUI), or colored green (in
15 the terminal). This marks the message as an *eval-time message*, meaning that
16 the message was printed as a direct response to the file changing or being
17 loaded the first time. Other messages that might print to the `eval` section
18 are things like errors in your program, and one-time debugging messages.
19
20 Now that the copilot is running, whenever you change `test.alv` and save it, the
21 copilot will reload it and execute your new code. When you are done, you can
22 stop the copilot at any time by closing the GUI window or pressing `^C`
23 (control-C) in the terminal.
24
25 Let's start with a simple operator, [print][]: [print][] is used simply to print
26 messages to the copilot console. Enter the following in your file and save it:
27
28 (print "hello world!")
29
30 As soon as you save the file, you should notice two things happening:
31
32 1. The copilot will print two new lines:
33
34 changes to files: hello.alv
35 hello world!
36
37 In the first line, it notifies us that the file has changed. In the second
38 line, you can see the output from the [print][] expression.
39 2. The copilot will make a small modification to your file. Depending on the
40 editor you are using, this may either result in you seeing the modification
41 immediately, or a notice appearing that offers the option to reload the
42 file. If it is the latter, confirm the notification to accept the changes.
43 If there is an option to do so, you may want to configure your editor to
44 always reload the file automatically.
45
46 The code should now look like this:
47
48 ([1]print "hello world")
49
50 The `[1]` that the copilot added to your expression is that expression's `tag`.
51 In `alv`, every expression has a tag that helps the copilot to identify the
52 individual expressions as you make changes to your code. The copilot will make
53 sure that all expressions are tagged by adding missing tags when you save the
54 file, but you have to watch out not to duplicate a tag when copying and pasting
55 code. When you duplicate code that already has tags, you can either manually
56 change the tags to be unique, or simply delete the whole tag (including the
57 square brackets) and let the copilot generate a new one for you the next time
58 you save the file.
1919 [on github][:*repo*:], and is licensed under [GPLv3][license].
2020
2121 If you want to learn more or try out `alv` yourself, the
22 [getting started][guide] page is a good place to start. On the other hand, if
22 [getting started guide][guide] is a good place to start. On the other hand, if
2323 you are a curious about the motivations and concepts behind `alv`, you can find
2424 more in-depth information on these topics in the
2525 ['persistent expressions' article][rationale].
2626
27 [guide]: guide/getting-started-guide.html
27 [guide]: guide/index.html
2828 [rationale]: https://s-ol.nu/alivecoding
2929 [license]: https://github.com/s-ol/alive/blob/master/LICENSE
0 So far, `alv` may seem a lot like any other programming language - you write
1 some code, save the file, and it runs, printing some output. "What about the
2 'continuously running' aspect from the introduction?", you may ask yourself.
3
4 So far, we have only seen *evaltime* execution in alv - but there is also
5 *runtime* behavior. At *evaltime*, that is whenever there is change to the
6 source code, `alv` behaves similar to a Lisp. This is the part we have seen
7 so far. But once one such *eval cycle* has executed, *runtime* starts, and
8 `alv` behaves like a dataflow system like [PureData][pd], [Max/MSP][max] or
9 [vvvv][vvvv].
10
11 What looked so far like static constants are actually *streams* of values.
12 Whenever an input to an operator changes, the operator (may) update and respond
13 with a change to its output as well. To see this in action, we need to start
14 with a changing value. Number literals like `1` and `2`, which we used so far,
15 are *evaltime constant*, which means simply that they will never update. Since
16 all inputs to our [math/+][] operator are *evaltime constant*, the result is
17 constant as well. To get some *runtime* activity, we have to introduce a
18 side-effect input from somewhere outside the system.
19
20 The [time/][] module contains a number of operators whose outputs update
21 over time. Lets take a look at [time/tick][]:
22
23 (import* time)
24 (trace (tick 1))
25
26 This will print a series of numbers, incrementing by 1 every second. The
27 parameter to [time/tick][] controls how quickly it counts - try changing it to
28 `0.5` or `2`. As you can see, we can change [time/tick][] *while it is
29 running*, but it doesn't lose track of where it was!
30
31 All of the other things we learned above apply to streams of values as well -
32 we can use [def][] to store them in the scope, transform them using the ops
33 from the [math/][] module and so on:
34
35 (import* time math)
36 (def tik (tick 0.25))
37 (trace (/ tik 4))
38
39 Note that if you leave the [time/tick][]'s *tag* in place when you move it into
40 the [def][] expression, it will keep on running steadily even then.
41
42 [pd]: http://puredata.info/
43 [max]: https://cycling74.com/products/max
44 [vvvv]: https://vvvv.org/
0 Both [import][] and [import*][] are actually shorthands and what they
1 accomplish can be done using the lower-level builtins [def][], [use][] and
2 [require][]. Here is how you could replace [import][]:
3
4 #(with import:)
5 (import math)
6 (trace (math/+ 1 2))
7
8 #(with def and require:)
9 (def math (require "math"))
10 (trace (math/+ 1 2))
11
12 [require][] returns a *scope*, which is defined as the symbol `math`.
13 Then `math/+` is resolved by looking for `+` in this nested scope. Note that
14 the symbol that the scope is defined as and the name of the module that is
15 loaded do not have to be the same, you could call the alias whatever you want:
16
17 #(this not possible with import!)
18 (def fancy-math (require "math"))
19 (trace (fancy-math/+ 1 2))
20
21 Most of the time the name of the module makes a handy prefix already, so
22 [import][] can be used to save a bit of typing and make the code look a bit
23 cleaner. [import*][], on the other hand, defines every symbol from the imported
24 module individually. It could be implemented with [use][] like this:
25
26 (use (require "math"))
27 (trace (+ 1 2))
28
29 [use][] copies all symbol definitions from the scope it is passed to the
30 current scope.
31
32 Note that [import][], [import*][], [def][], and [use][] all can take multiple
33 arguments:
34
35 #(using the shorthands:)
36 (import* math logic)
37 (import midi osc)
38
39 #(using require, use and def:)
40 (use (require "math") (require "logic"))
41 (def midi (require "midi")
42 osc (require "osc"))
43
44 It is common to have an [import][] and [import*][] expression at the top of an
45 `alv` program to load all of the modules that will be used later, but the
46 modules don't necessarily have to be loaded at the very beginning, as long as
47 all symbols are defined before they are being used.
48
49 ## nested scopes
50 Once a symbol is defined, it cannot be changed or removed:
51
52 (def a 3)
53 (def a 4) #(error!)
54
55 It is, however, possible to 'shadow' a symbol by re-defining it in a nested
56 scope: So far, all symbols we have defined - using `def`, [import][] and
57 [import*][] - have been defined in the *global scope*, the scope that is active
58 in the whole `alv` program. The [do][] builtin can be used to create a new
59 scope and evaluate some expressions in it:
60
61 (import string)
62
63 (def a 1
64 b 2)
65
66 (trace (.. "first: " a " " b))
67 (do
68 (def a 3)
69 (trace (.. "second: " a " " b))
70 (trace (.. "third: " a " " b))
71
72 This example prints the following:
73
74 trace (.. "first: " a " " b): <Value str: first: 1 2>
75 trace (.. "second: " a " " b): <Value str: second: 3 2>
76 trace (.. "third: " a " " b): <Value str: third: 1 2>
77
78 As you can see, within a nested scope it is possible to overwrite a definition
79 from the parent scope. Symbols that are not explicitly redefined in a nested
80 scope keep their values, and changes in the nested scope do not impact the
81 parent scope.
0 Another builtin that creates a nested scope is [fn][], which is used to
1 create a *user-defined function*, which can be used to simplify repetitive
2 code, amongst other things:
3
4 (import* math)
5
6 (def add-and-trace
7 (fn
8 (a b)
9 (trace (+ a b))))
10
11 (add-and-trace 1 2)
12 (add-and-trace 3 4)
13
14 Here a *function* `add-and-trace` is defined. When defining a function, first
15 the names of the parameters have to be given. The function defined here takes
16 two parameters, `a` and `b`. The last part of the function definition is called
17 the *function body*.
18
19 A function created using [fn][] can be called just like an operator. When a
20 function is called, the parameters to the function are defined with the names
21 given in the definition, and then the function body is executed. The previous
22 example is equivalent to the following:
23
24 (import* math)
25
26 (def add-and-trace
27 (fn
28 (a b)
29 (trace (+ a b)))
30
31 (do
32 (let a 1
33 b 2)
34 (trace (+ a b)))
35
36 (do
37 (let a 3
38 b 4)
39 (trace (+ a b)))
40
41 and the output of both is:
42
43 trace (+ a b): <num= 3>
44 trace (+ a b): <num= 7>
45
46 In `alv`, functions are first-class values and can be passed around just like
47 numbers, strings, etc. However it is very common to define a function with a
48 name, so there is the `defn` shorthand, which combines the `def` and `fn`
49 builtins into a single expression. Compare this equivalent definition of the
50 `add-and-trace` function:
51
52 (defn add-and-trace (a b)
53 (trace (+ a b)))
0 __This section is currently under construction.__
1
2 This reference manual documents the `alv` langauge and its standard facilities
3 in detail. If you are new to alive, the [getting started guide][guide] is the
4 recommended place to start. If you are looking for information on adding your
5 own module or contributing to alive, check out the
6 [developer documentation](../internals/index.html).
7
8 [guide]: (../guide/index.html)
9
10 ## contents
11
12 1. syntax
13 2. [evaltime and runtime](02_evaltime-and-runtime.html)
14 3. evaltime
15 1. [symbol resolution](03-1_symbol-resolution.html)
16 2. if and switch
17 3. [functions](03-3_functions.html)
18 4. dynamic symbols
19 5. loops
20 6. modules and loading
21 4. runtime
22 1. result kinds
23 2. pure operators
24 5. [builtin listing](builtins.html)
25 6. included modules
6161
6262 ul, ol {
6363 margin: 0.5em 0;
64 padding-left: 0.6em;
64 padding-left: 1em;
6565 }
6666 ul, .ldoc ol { list-style: '- '; }
67 li > ul, li > ol { margin: 0; }
6768
6869 header {
6970 position: fixed;