docs
This commit is contained in:
parent
2a8a7b347e
commit
859afa2b94
21 changed files with 1139 additions and 3 deletions
25
README.md
25
README.md
|
@ -1,7 +1,26 @@
|
|||
# talc
|
||||
# Talc
|
||||
|
||||
## installation
|
||||
Talc is a dynamically-typed functional programming language designed primarily
|
||||
for use as a terminal calculator.
|
||||
|
||||
```sh
|
||||
## Installation
|
||||
|
||||
Talc is written in Rust and requires at least version 1.81 to compile.
|
||||
|
||||
```bash
|
||||
cargo install --profile release-opt --path talc-bin
|
||||
```
|
||||
|
||||
Read the documentation for more info.
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation is available online at [TODO](TODO).
|
||||
|
||||
To build the documentation locally, install
|
||||
[mdBook](https://rust-lang.github.io/mdBook/) and run the following from the
|
||||
`docs/` directory:
|
||||
|
||||
```bash
|
||||
mdbook serve --open
|
||||
```
|
||||
|
|
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
book
|
6
docs/book.toml
Normal file
6
docs/book.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[book]
|
||||
authors = ["trimill"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "Talc"
|
24
docs/src/SUMMARY.md
Normal file
24
docs/src/SUMMARY.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
- [Introduction](./introduction.md)
|
||||
|
||||
# Installation
|
||||
|
||||
- [Installation](./install/installation.md)
|
||||
- [Tour of the REPL](./install/repl.md)
|
||||
|
||||
# The language
|
||||
|
||||
- [Arithmetic](./lang/arithmetic.md)
|
||||
- [Bitwise operators](./lang/bitwise.md)
|
||||
- [Operators reference](./lang/operators.md)
|
||||
- [Variables and scope](./lang/variables.md)
|
||||
- [Functions](./lang/functions.md)
|
||||
- [Partial functions and pipes](./lang/partial.md)
|
||||
- [Strings and symbols](./lang/strings.md)
|
||||
- [Lists](./lang/lists.md)
|
||||
- [Tables](./lang/tables.md)
|
||||
- [Control flow](./lang/controlflow.md)
|
||||
- [Iterators](./lang/iterators.md)
|
||||
- [Ranges](./lang/ranges.md)
|
||||
- [Exceptions](./lang/exceptions.md)
|
||||
|
||||
|
17
docs/src/install/installation.md
Normal file
17
docs/src/install/installation.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Installation
|
||||
|
||||
To install Talc, first you must install the Rust programming language. Follow
|
||||
[the instructions here](https://doc.rust-lang.org/book/ch01-01-installation.html)
|
||||
to do so. Talc requires at least Rust 1.81.
|
||||
|
||||
Once Rust is installed, clone
|
||||
[the Talc repository](https://g.trimill.xyz/trimill/talc) and, from the root of
|
||||
the repository, run:
|
||||
|
||||
```bash
|
||||
cargo install --profile release-opt --path talc-bin
|
||||
```
|
||||
|
||||
This will build and install the Talc REPL. To run Talc, run `talc` (ensuring
|
||||
that Cargo's installation path is part of your `$PATH`). For information about
|
||||
command-line arguments, use `talc --help`.
|
36
docs/src/install/repl.md
Normal file
36
docs/src/install/repl.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Tour of the REPL
|
||||
|
||||
To begin using Talc, launch the REPL by running `talc` with no arguments.
|
||||
This chapter will showcase various features of the REPL environment. If you do
|
||||
not understand any, try coming back to this chapter after reading the rest of
|
||||
the book.
|
||||
|
||||
## Using the REPL
|
||||
|
||||
To use the REPL, simply enter an expression after the prompt (`>> `). If your
|
||||
terminal supports it, entered text will be syntax-highlighted. To disable this,
|
||||
use the argument `--color=never`. To force coloring even when support is not
|
||||
detected, use `--color=always`.
|
||||
|
||||
To evaluate the expression, press Enter. If the input is incomplete (eg. some
|
||||
delimiter is unmatched) the prompt will continue onto the next line.
|
||||
|
||||
## Previous results
|
||||
|
||||
The special global variables `_`, `__`, and `___` store the result of the
|
||||
previous, second previous, and third previous results. Expressions that yield
|
||||
a syntax or compile error or exception are skipped over.
|
||||
|
||||
## History
|
||||
|
||||
Use the up and down arrows to cycle through previous entries. By specifiying
|
||||
a history file with the `-H`/`--histfile` argument, history can be preserved
|
||||
between sessions.
|
||||
|
||||
## Advanced features
|
||||
|
||||
Use the `-a`/`--show-ast` flag to print the AST generated from the expression.
|
||||
Use the `-d`/`--disasm` flag to show the disassembled bytecode generated by the
|
||||
compiler.
|
||||
The `--no-opt` flag disables the optimization step, which may affect the
|
||||
bytecode but should not affect behavior.
|
36
docs/src/introduction.md
Normal file
36
docs/src/introduction.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Introduction
|
||||
|
||||
Talc is a dynamically-typed functional programming language designed primarily
|
||||
for use as a terminal calculator.
|
||||
|
||||
Expand the sidebar to view installation instructions and a guide for using
|
||||
Talc.
|
||||
|
||||
```talc
|
||||
>> -- Basic arithmetic
|
||||
>> 2*(6+3i) + ln(4) / sin(tau/5)
|
||||
13.457636152392087+6.0i
|
||||
|
||||
>> -- Large integers
|
||||
>> factors(2^107+1)
|
||||
[3, 643, 84115747449047881488635567801]
|
||||
|
||||
>> -- Binary operations
|
||||
>> bin(0xffff #& ~(0x1234 #& 0b10001101))
|
||||
"1111111111111011"
|
||||
|
||||
>> -- Functions
|
||||
>> dist = \x1,y1,x2,y2 -> sqrt((x1-x2)^2 + (y1-y2)^2)
|
||||
<anon function(4) @57c274b03fc0>
|
||||
>> dist(2, 3, 4, 4)
|
||||
2.23606797749979
|
||||
|
||||
>> -- Pipeline syntax
|
||||
>> [2, 4, 6, 8, 10] | map(\x -> x^2) | sum | factors | count
|
||||
{ 2=2, 5=1, 11=1 }
|
||||
|
||||
>> -- Project Euler question 1
|
||||
>> 0..1000 | filter(\x -> (x%3 == 0 or x%5 == 0)) | sum
|
||||
233168
|
||||
```
|
||||
|
130
docs/src/lang/arithmetic.md
Normal file
130
docs/src/lang/arithmetic.md
Normal file
|
@ -0,0 +1,130 @@
|
|||
# Arithmetic
|
||||
|
||||
The most natural use for a calculator is to calculate. The Talc REPL will
|
||||
evaluate any expression you enter and print the result.
|
||||
|
||||
```talc
|
||||
>> 2 + 3
|
||||
5
|
||||
>> 10^2 + 5*6
|
||||
130
|
||||
```
|
||||
|
||||
All the above operations were performed on **integers**. To operate on
|
||||
fractional numbers (**floats**), enter numbers with a decimal point:
|
||||
|
||||
```talc
|
||||
>> 2.0 + 3.0
|
||||
5.0
|
||||
>> 1.0 / 3.0
|
||||
0.3333333333333333
|
||||
>> 1.2e3
|
||||
1200.0
|
||||
>> 0.1 + 0.2
|
||||
0.30000000000000004
|
||||
>> 0.1 + 0.2 == 0.3
|
||||
false
|
||||
```
|
||||
|
||||
Note that arithmetic on floats in Talc, as with other languages, may be
|
||||
imprecise. For exact arithmetic on fractional numbers, use **ratios**:
|
||||
|
||||
```talc
|
||||
>> 1/10 + 2/10
|
||||
3/10
|
||||
>> 1/10 + 2/10 == 3/10
|
||||
true
|
||||
```
|
||||
|
||||
Talc also supports **complex floats**, writing imaginary numbers with an `i`
|
||||
suffix:
|
||||
|
||||
```talc
|
||||
>> (1 + 2i)*(3 - 1i)
|
||||
5.0+5.0i
|
||||
>> 1i^1i
|
||||
0.20787957635076193+0.0i
|
||||
```
|
||||
|
||||
So far, we have seen five operators: addition (`+`), subtraction (`-`),
|
||||
multiplication (`*`), division (`/`), and powers (`^`). Talc also supports
|
||||
(Euclidean) integer division using `//` and the modulo operator `%`. A unary
|
||||
minus can be used to negate a number or expression.
|
||||
|
||||
We have also seen parentheses (`( )`) used for grouping expressions. Operator
|
||||
precendence follows mathematical convention, for a complete specification see
|
||||
the [operator reference](./operators.md).
|
||||
|
||||
When an operation is performed on numbers of different types, one is
|
||||
automatically coerced into the type of the other. Coercion goes along the
|
||||
following heirarchy: `int -> ratio -> float -> complex`. The type of the result
|
||||
is generally the same as the type of the inputs, with some exceptions:
|
||||
|
||||
- Division on integers yields a ratio
|
||||
- An integer to a negative integer power yields a ratio (a nonnegative power
|
||||
will still yield an integer)
|
||||
- A ratio to a ratio power yields a float (a ratio to an integer power
|
||||
still yields a ratio)
|
||||
|
||||
Multiple expressions may be written on the same line of the REPL by separating
|
||||
them with semicolons. Only the value of the final one will be printed.
|
||||
|
||||
```talc
|
||||
>> x = 5; x += 1; x * 2
|
||||
12
|
||||
```
|
||||
|
||||
## Comparison and booleans
|
||||
|
||||
To compare two values, use the equality operators `==` (equal) or `!=`
|
||||
(inequal), or the comparison operators `>` (greater), `<` (less), `>=`
|
||||
(greater or equal), and `<=` (less or equal). These also coerce their arguments
|
||||
automatically. Complex numbers cannot be compared.
|
||||
|
||||
Equality and comparison operators evaluate to a *boolean*: either `true` or
|
||||
`false`.
|
||||
|
||||
```talc
|
||||
>> 1 + 2 == 3
|
||||
true
|
||||
>> 5 < 3.0
|
||||
false
|
||||
>> 1/2 >= 0.5
|
||||
true
|
||||
>> 1 + 3i < 5
|
||||
Error: type_error: cannot compare 1.0+3.0i and 5
|
||||
```
|
||||
|
||||
The boolean operators `and`, `or`, and `not` perform the expected operations
|
||||
on booleans. Like in many other languages, `and` and `or`
|
||||
[short-circuit](https://en.wikipedia.org/wiki/Short-circuit_evaluation).
|
||||
|
||||
```talc
|
||||
>> 1 < 2 and 3 < 4
|
||||
true
|
||||
>> 1 > 2 or not 5 == 6
|
||||
true
|
||||
>> x = 5
|
||||
5
|
||||
>> 1 == 2 and (x += 3) == 8
|
||||
false
|
||||
>> x
|
||||
5
|
||||
```
|
||||
|
||||
`and`, `or`, and `not` can also be used on non-boolean values. Some Talc values
|
||||
are considered *falsy* and coerce to `false` under such operations, these are
|
||||
listed below.
|
||||
- The boolean `false`
|
||||
- The value `nil`
|
||||
- A number equal to zero
|
||||
- An empty range, string, list, or table
|
||||
- A cell containing a falsy value
|
||||
|
||||
All other values are considered *truthy*, notably `true`, all nonzero numbers
|
||||
(including `NaN`), nonempty collections, symbols, and functions.
|
||||
|
||||
The operators behave as follows
|
||||
- `x and y` evaluates to `y` if `x` is truthy and to `x` if `x` is truthy
|
||||
- `x or y` evaluates to `x` if `x` is truthy and to `y` if `x` is falsy
|
||||
- `not x` evaluates to `true` if x is falsy and `false` if x is truthy
|
27
docs/src/lang/bitwise.md
Normal file
27
docs/src/lang/bitwise.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Bitwise operators
|
||||
|
||||
While most operators treat their operands as numbers, *bitwise operators*
|
||||
consider the underlying binary representation. As such, these can only be
|
||||
applied to integers.
|
||||
|
||||
```talc
|
||||
>> 5 #& 12 -- bitwise AND
|
||||
4
|
||||
>> 5 #| 12 -- bitwise OR
|
||||
13
|
||||
>> 5 #^ 12 -- bitwise XOR
|
||||
9
|
||||
>> ~5 -- bitwise NOT
|
||||
-6
|
||||
>> 5 >> 2 -- shift right
|
||||
1
|
||||
>> 5 << 2 -- shift left
|
||||
20
|
||||
```
|
||||
|
||||
Integers are represented using
|
||||
[two's complement](https://en.wikipedia.org/wiki/Two%27s_complement), so `~x`
|
||||
is equivalent to `-x - 1`. Bitwise operations work as expected on large
|
||||
integers - negative numbers are considered to have an infinite trail of ones
|
||||
to the left (mirroring the infinite trail of zeroes present on positive
|
||||
numbers).
|
92
docs/src/lang/controlflow.md
Normal file
92
docs/src/lang/controlflow.md
Normal file
|
@ -0,0 +1,92 @@
|
|||
# Control flow
|
||||
|
||||
Although Talc is a functional language, it also has imperative-style control
|
||||
flow.
|
||||
|
||||
## If statement
|
||||
|
||||
The if-statement can be used to conditionally execute some code.
|
||||
|
||||
```talc
|
||||
if 1 == 2 then
|
||||
println("this will never print!")
|
||||
end
|
||||
```
|
||||
|
||||
Multiple `elif` clauses can be chained to an `if` to add alternate conditions,
|
||||
and a final `else` clause can also be used if none of the previous clauses'
|
||||
conditions are satisfied.
|
||||
|
||||
```talc
|
||||
if 1 == 2 then
|
||||
println("nope")
|
||||
elif 3 == 4 then
|
||||
println("not yet")
|
||||
elif 5 == 5 then
|
||||
println("here!")
|
||||
else
|
||||
println("too late.")
|
||||
end
|
||||
```
|
||||
|
||||
Like `do ... end` blocks, if-statements create a new scope for each of their
|
||||
bodies.
|
||||
|
||||
Since every statement in Talc is an expression, it is meaningful to speak of
|
||||
the value of an if-statement; this is just the value of whichever block is
|
||||
evaluated.
|
||||
|
||||
```
|
||||
>> -- note: there is a builtin function also named "abs"
|
||||
>> abs = \x -> if x < 0 then -x else x end
|
||||
<anon function(1) @5661c4350f40>
|
||||
>> abs(3)
|
||||
3
|
||||
>> abs(-5)
|
||||
5
|
||||
```
|
||||
|
||||
If an `else` clause is missing and no condition is satisfied, the if-statement
|
||||
will evaluate to `nil`.
|
||||
|
||||
## For loop
|
||||
|
||||
The `for` loop can be used to iterate over the values of a collection (or
|
||||
[iterator](./iterators.md)). The body will be run once per item, with the
|
||||
loop variable's value being that item.
|
||||
|
||||
```talc
|
||||
# prints each animal on a new line
|
||||
|
||||
animals = ["cat", "elephant", "zebra", "goose"]
|
||||
|
||||
for a in animals do
|
||||
println(a)
|
||||
end
|
||||
```
|
||||
|
||||
## While loop
|
||||
|
||||
The `while` loop can be used to repeat a section of code while a condition is
|
||||
satisfied.
|
||||
|
||||
```talc
|
||||
# prints the numbers 0, 1, 2, 5, 26, and 667, each on their own line
|
||||
|
||||
n = 0
|
||||
|
||||
while n < 1000 do
|
||||
println(n)
|
||||
n = n^2 + 1
|
||||
end
|
||||
```
|
||||
|
||||
## Break and Continue
|
||||
|
||||
The `break` and `continue` expressions can be used to exit a loop early or
|
||||
skip to the next iteration. They always only affect the innermost loop.
|
||||
|
||||
`break` can optionally be provided an argument, e.g. `break 5`. If a loop is
|
||||
exited using a `break` statement, the resulting value will be the value passed
|
||||
to `break`, or `nil` if none was passed. If the loop exits normally, its value
|
||||
is always `nil`.
|
33
docs/src/lang/exceptions.md
Normal file
33
docs/src/lang/exceptions.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Exceptions
|
||||
|
||||
When an error occurs during execution of a program, an *exception* is thrown.
|
||||
Exceptions propagate backwards through function calls until an appropriate
|
||||
try-catch block is found.
|
||||
|
||||
To throw an exception, use the standard library function `throw`. The first
|
||||
argument is a symbol representing the type of exception, the second is a
|
||||
message (which must be a string).
|
||||
|
||||
```talc
|
||||
>> throw(:my_exception, "something bad happened!")
|
||||
Error: my_exception: something bad happened!
|
||||
```
|
||||
|
||||
The exception can then be caught in a try-catch block:
|
||||
|
||||
```talc
|
||||
try
|
||||
println("1 / 0 = " ++ str(1/0))
|
||||
catch :value_error in exc do
|
||||
println("oops, can't divide by zero")
|
||||
end
|
||||
```
|
||||
|
||||
Each catch block may specify multiple exception types to match (separated by
|
||||
commas), or an asterisk (`*`) to match all exceptions. The following portion
|
||||
(to capture the exception into a variable) is optional. Multiple catch blocks
|
||||
may be present and will be checked in order until a matching one is found.
|
||||
|
||||
Pressing `Ctrl`+`C` in the REPL will cause the VM to create an `:interrupted`
|
||||
exception. This will always be detected quickly for Talc-native code but some
|
||||
standard library functions might not check for this.
|
67
docs/src/lang/functions.md
Normal file
67
docs/src/lang/functions.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Functions
|
||||
|
||||
Talc is a functional language, so many features are built on top of functions
|
||||
and function application. As such, there are a few ways to define a function.
|
||||
The simplest creates an anonymous (sometimes called "lambda") function using
|
||||
a backslash (`\`). Since functions are first-class, we can assign the
|
||||
newly-created function to a variable:
|
||||
|
||||
```talc
|
||||
>> square = \x -> x^2
|
||||
<anon function(1) @58e147c2f250>
|
||||
>> square(5)
|
||||
25
|
||||
```
|
||||
|
||||
Functions may take multiple arguments:
|
||||
|
||||
```talc
|
||||
>> area = \width,height -> width*height
|
||||
<anon function(2) @58e147c30b50>
|
||||
>> area(3, 6)
|
||||
18
|
||||
```
|
||||
|
||||
For simple one-argument functions, the parameter list can be omitted by using
|
||||
an ampersand instead of a backslash. The single argument's name is the special
|
||||
variable `$`:
|
||||
|
||||
```talc
|
||||
>> square = &$^2
|
||||
<anon function(1) @58e147c31950>
|
||||
>> square(5)
|
||||
25
|
||||
```
|
||||
|
||||
As seen above, calling a function can be done by writing the arguments in
|
||||
parentheses separated by commas immediately after the function.
|
||||
|
||||
An alternate function definition syntax allows you to name the function and is
|
||||
more suitable for scripting:
|
||||
|
||||
```talc
|
||||
fn square(x) do
|
||||
x^2
|
||||
end
|
||||
|
||||
println(square(5)) -- prints 25
|
||||
```
|
||||
|
||||
By default, the value returned from a function is the value of the last
|
||||
expression in the function's body. To return early, use the `return` keyword.
|
||||
This will be more useful once we have seen other methods of control flow.
|
||||
|
||||
```talc
|
||||
fn counting(amount) do
|
||||
if amount < 0 then
|
||||
println("I can't count backward!")
|
||||
return
|
||||
end
|
||||
for i in 1..=amount do
|
||||
println(i)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
For more advanced use of functions, see
|
||||
[Partial functions and pipes](./partial.md).
|
142
docs/src/lang/iterators.md
Normal file
142
docs/src/lang/iterators.md
Normal file
|
@ -0,0 +1,142 @@
|
|||
# Iterators
|
||||
|
||||
Iterators are one of the most powerful features of the Talc language and
|
||||
standard library. An iterator is represented with a zero-argument function.
|
||||
Every time the function is called it returns the next item in the sequence,
|
||||
or the special value `:end_iteration` to signal that no more items are
|
||||
available.
|
||||
|
||||
An iterator can be created simply by defining such a function:
|
||||
|
||||
```talc
|
||||
>> n = 0
|
||||
0
|
||||
>> fn counting() do
|
||||
if n == 3 then
|
||||
return :end_iteration
|
||||
end
|
||||
n += 1
|
||||
n
|
||||
end
|
||||
<function counting(0) @5661c434f760>
|
||||
>> counting()
|
||||
1
|
||||
>> counting()
|
||||
2
|
||||
>> counting()
|
||||
3
|
||||
>> counting()
|
||||
:end_iteration
|
||||
>> counting()
|
||||
:end_iteration
|
||||
```
|
||||
|
||||
Much like lists and ranges, iterators can be used in a `for` loop. In fact,
|
||||
lists and ranges are converted to iterators automatically by the `for` loop.
|
||||
This can be done manually using the built-in `iter` function:
|
||||
|
||||
```talc
|
||||
>> lst = [2, 3, 5]
|
||||
[2, 3, 5]
|
||||
>> lst_iter = iter(lst)
|
||||
<native function iter[list](0) @5661c4352ef0>
|
||||
>> lst_iter()
|
||||
2
|
||||
>> lst_iter()
|
||||
3
|
||||
>> lst_iter()
|
||||
5
|
||||
>> lst_iter()
|
||||
:end_iteration
|
||||
```
|
||||
|
||||
An iterator can be converted to a list using the `list` function:
|
||||
|
||||
```talc
|
||||
>> lst = [2, 3, 5]
|
||||
[2, 3, 5]
|
||||
>> list(iter(lst))
|
||||
[2, 3, 5]
|
||||
```
|
||||
|
||||
## Iterator functions
|
||||
|
||||
The standard library includes many functions to manipulate iterators. Some
|
||||
essential ones are listed here. Examples will show both conventional call
|
||||
syntax as well as a version using a pipeline.
|
||||
|
||||
All standard library functions will take the iterator as the final argument.
|
||||
|
||||
### Map
|
||||
|
||||
`map` creates a new iterator from an existing one by passing each element
|
||||
through a provided function.
|
||||
|
||||
```talc
|
||||
>> list(map(\x -> x^2, [2, 3, 5]))
|
||||
[4, 9, 25]
|
||||
>> [2, 3, 5] | map(\x -> x^2) | list
|
||||
[4, 9, 25]
|
||||
```
|
||||
|
||||
### Filter
|
||||
|
||||
`filter` creates a new iterator only including values that, when passed to the
|
||||
provided function, return a truthy value.
|
||||
|
||||
```talc
|
||||
>> list(filter(\x -> x % 3 != 0, [1, 2, 3, 4, 5, 6]))
|
||||
[1, 2, 4, 5]
|
||||
>> [1, 2, 3, 4, 5, 6] | filter(\x -> x % 3 != 0) | list
|
||||
[1, 2, 4, 5]
|
||||
```
|
||||
|
||||
### Fold
|
||||
|
||||
`fold` consumes an iterator, applying a two-argument function repeatedly to its
|
||||
values.
|
||||
|
||||
```talc
|
||||
>> fold(\x,y -> x*y, [1, 2, 3, 4, 5, 6])
|
||||
720
|
||||
>> [1, 2, 3, 4, 5, 6] | fold(\x,y -> x*y)
|
||||
720
|
||||
```
|
||||
|
||||
`foldi` does the same but allows an initial value to be specified.
|
||||
|
||||
```talc
|
||||
>> foldi(11, \x,y -> x/y, [1, 2, 3, 4, 5, 6])
|
||||
720
|
||||
>> [1,2,3,4,5,6] | foldi(11, \x,y -> x/y)
|
||||
720
|
||||
```
|
||||
|
||||
`sum` and `prod` consume an iterator and return the sum or product of its
|
||||
elements, respectively.
|
||||
|
||||
### Forever and Take
|
||||
|
||||
`forever` creates an iterator that returns the given value every time it is
|
||||
called - an endless iterator. It is useful in combination with `take`, which
|
||||
creates an iterator that returns only the first *n* elements of its argument.
|
||||
|
||||
```talc
|
||||
>> list(take(10, forever(42)))
|
||||
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
|
||||
>> forever(42) | take(10) | list
|
||||
[42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
|
||||
>> forever(42) | list -- bad idea!
|
||||
```
|
||||
|
||||
### Enumerate
|
||||
|
||||
`enumerate` creates an iterator of two-element arrays, the first is the index
|
||||
(starting from `0`) and the second is the item from the original iterator.
|
||||
|
||||
```
|
||||
>> list(enumerate(["a", "b", "c"]))
|
||||
[[0, "a"], [1, "b"], [2, "c"]]
|
||||
>> ["a", "b", "c"] | enumerate | list
|
||||
[[0, "a"], [1, "b"], [2, "c"]]
|
||||
```
|
48
docs/src/lang/lists.md
Normal file
48
docs/src/lang/lists.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
# Lists
|
||||
|
||||
Lists in Talc are written as comma-separated items between square brackets.
|
||||
Lists may be *heterogeneous* (contain items of different types). Similarly to
|
||||
strings, lists may be concatenated using `++`. Lists can be indexed by writing
|
||||
the index in square brackets after the list. The first element of the list is
|
||||
at index zero.
|
||||
|
||||
```talc
|
||||
>> numbers = [1, 5, 6, 4, 2, 3]
|
||||
[1, 5, 6, 4, 2, 3]
|
||||
>> numbers[3]
|
||||
4
|
||||
>> numbers ++ [8, 9]
|
||||
[1, 5, 6, 4, 2, 3, 8, 9]
|
||||
```
|
||||
|
||||
Lists are *mutable* and their elements can be assigned to or modified.
|
||||
|
||||
```talc
|
||||
>> animals = ["cat", "dog", "elephant"]
|
||||
["cat", "dog", "elephant"]
|
||||
>> animals[1] = "moose"
|
||||
"moose"
|
||||
>> animals
|
||||
["cat", "moose", "elephant"]
|
||||
```
|
||||
|
||||
Use the built-in function `len` to get the length of a list.
|
||||
|
||||
```talc
|
||||
>> languages = ["C", "Rust", "Haskell", "Lua"]; len(languages)
|
||||
4
|
||||
```
|
||||
|
||||
*Ranges* can also be used to get a subsequence of a list. We will discuss
|
||||
ranges further in their own chapter.
|
||||
|
||||
```talc
|
||||
>> squares = [0, 1, 4, 9, 16, 25, 36, 49]
|
||||
[0, 1, 4, 9, 16, 25, 36, 49]
|
||||
>> squares[1..4]
|
||||
[1, 4, 9]
|
||||
>> squares[3..*]
|
||||
[9, 16, 25, 36, 49]
|
||||
>> squares[*..-3]
|
||||
[0, 1, 4, 9, 16]
|
||||
```
|
38
docs/src/lang/operators.md
Normal file
38
docs/src/lang/operators.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Operators reference
|
||||
|
||||
In increasing order of precedence:
|
||||
|
||||
| Operator | Kind | Description |
|
||||
|------------------|--------|------------------------------------------|
|
||||
| `=` | Right | Assignment |
|
||||
| `\|` | Left | Pipeline |
|
||||
| `\ &` | Prefix | Function definition |
|
||||
| `or` | Left | Boolean disjunction |
|
||||
| `and` | Left | Boolean conjunction |
|
||||
| `not` | Prefix | Boolean negation |
|
||||
| `= != > >= < <=` | None | Equality and inequality |
|
||||
| `++` | Left | Concatenation |
|
||||
| `&` | Left | Append |
|
||||
| `.. ..=` | None | Range (exclusive and inclusive) |
|
||||
| `*.. *..=` | Prefix | Range to (exclusive and inclusive) |
|
||||
| `..*` | Suffix | Range from |
|
||||
| `#\|` | Left | Bitwise OR |
|
||||
| `#^` | Left | Bitwise XOR |
|
||||
| `#&` | Left | Bitwise AND |
|
||||
| `<< >>` | Left | Shift left and right |
|
||||
| `+ -` | Left | Add and subtract |
|
||||
| `* / // %` | Left | Multiply, divide, integer divide, modulo |
|
||||
| `- ~` | Prefix | Negation and bitwise NOT |
|
||||
| `^` | Right | Power |
|
||||
| `() [] . ->` | Left | Call, index, access, associated call |
|
||||
|
||||
"Prefix" and "Suffix" denote unary operators placed before or after an
|
||||
expression. "Left", "Right", and "None" denote binary operators that are left-,
|
||||
right-, or not associative.
|
||||
|
||||
All three sets of range operators (`.. ..= *.. *..= ..*`) have the same
|
||||
precedence level, despite being listed seperately.
|
||||
|
||||
Augmented assignment operators (
|
||||
`++= &= #|= #^= #&= <<= >>= += -= *= /= //= %= ^=`) have the same
|
||||
precedence and associativity as ordinary assignment.
|
54
docs/src/lang/partial.md
Normal file
54
docs/src/lang/partial.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
# Partial functions
|
||||
|
||||
If a function is supplied with more arguments than it expects, it will throw
|
||||
an exception. If it is supplied with too few arguments, however, it will return
|
||||
a *partially-applied function* (or partial function for short). This value may
|
||||
then be called with the remaining arguments and the expected result will be
|
||||
returned.
|
||||
|
||||
```talc
|
||||
>> add_nums = \x,y,z -> x + y + z
|
||||
<anon function(3) @58e147c31910>
|
||||
>> add_nums(5, 6, 8)
|
||||
19
|
||||
>> add5 = add_nums(5)
|
||||
<anon native function(2) @58e147c329e0>
|
||||
>> add5_and6 = add5(6)
|
||||
<anon native function(1) @58e147c33360>
|
||||
>> add5_and6(8)
|
||||
19
|
||||
```
|
||||
|
||||
Note that each time the function is given an argument the number the result
|
||||
expects decreases by one.
|
||||
|
||||
## Pipes
|
||||
|
||||
An alternate way of calling a function with one argument is using the pipe
|
||||
operator (`|`). The order is reversed to a normal function call - the argument
|
||||
is written before the pipe.
|
||||
|
||||
```talc
|
||||
>> sin(2)
|
||||
0.9092974268256817
|
||||
>> 2 | sin
|
||||
0.9092974268256817
|
||||
```
|
||||
|
||||
Partial application combines very nicely with pipes: functions may first be
|
||||
called with all but one of their arguments, and the resulting partially-applied
|
||||
function may be called using a pipe.
|
||||
|
||||
```talc
|
||||
>> gcd(70, 15)
|
||||
5
|
||||
>> 15 | gcd(70)
|
||||
5
|
||||
```
|
||||
|
||||
Note that the argument to the left of the pipe becomes the *final* argument to
|
||||
the function. This is the opposite of langauges like Elixir, in which it
|
||||
becomes the initial argument.
|
||||
|
||||
Pipelines will be featured heavily in the chapter on
|
||||
[ranges and iterators](./iterators.md).
|
67
docs/src/lang/ranges.md
Normal file
67
docs/src/lang/ranges.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Ranges
|
||||
|
||||
In the previous chapter we showed how to build an iterator that produces
|
||||
numbers sequentially. To simplify this task, we can use *ranges*:
|
||||
|
||||
```talc
|
||||
>> numbers = 2..10
|
||||
2..10
|
||||
>> list(numbers)
|
||||
[2, 3, 4, 5, 6, 7, 8, 9]
|
||||
>> numbers | filter(\x -> x%2 == 1) | list
|
||||
[3, 5, 6, 9]
|
||||
```
|
||||
|
||||
There are six kinds of range, depending on whether the range is endless on one
|
||||
or both sides and if the ending bound is included or not
|
||||
|
||||
| Range | Description |
|
||||
|-------|-------------------------------------------|
|
||||
| 2..5 | Range from 2 to 5, excluding 5 |
|
||||
| 2..=5 | Range from 2 to 5, including 5 |
|
||||
| 2..* | Endless range starting at 2 |
|
||||
| *..5 | Endless range stopping before 5 |
|
||||
| *..=5 | Endless range stopping at 5 (including 5) |
|
||||
| *..* | Endless in both directions |
|
||||
|
||||
Only ranges with an initial value can be used as iterators.
|
||||
|
||||
## Ranges for indexing
|
||||
|
||||
Ranges can also be used to index a list, returning the sublist specified by the
|
||||
range.
|
||||
|
||||
```talc
|
||||
>> items = [5, 10, 15, 20, 25, 30]
|
||||
[5, 10, 15, 20, 25, 30]
|
||||
>> items[2..4]
|
||||
[15, 20]
|
||||
>> items[2..=4]
|
||||
[15, 20, 25]
|
||||
>> items[*..4]
|
||||
[5, 10, 15, 20]
|
||||
>> items[*..=4]
|
||||
[5, 10, 15, 20, 25]
|
||||
>> items[2..*]
|
||||
[15, 20, 25, 30]
|
||||
>> items[*..*]
|
||||
[5, 10, 15, 20, 25, 30]
|
||||
```
|
||||
|
||||
The same works for strings:
|
||||
|
||||
```talc
|
||||
>> "Hello, world!"[*..=4]
|
||||
"Hello"
|
||||
```
|
||||
|
||||
Negative indices will index starting at the back of the list:
|
||||
|
||||
```talc
|
||||
>> items[-3]
|
||||
20
|
||||
>> items[*..-1]
|
||||
[5, 10, 15, 20, 25]
|
||||
```
|
||||
|
||||
|
74
docs/src/lang/strings.md
Normal file
74
docs/src/lang/strings.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Strings and symbols
|
||||
|
||||
Strings in Talc can contain any sequence of bytes. When representing text, they
|
||||
conventionally contain UTF-8 encoded characters. String literals are written
|
||||
between a pair of single- or double-quotes. Double-quoted strings may contain
|
||||
escape sequences while single-quoted strings may not.
|
||||
|
||||
```talc
|
||||
>> "Hello, world!"
|
||||
"Hello, world!"
|
||||
>> "Write \"escapes\" with a backslash: \\"
|
||||
"Write \"escapes\" with a backslash: \\"
|
||||
>> 'No escape needed: \'
|
||||
"No escape needed: \\"
|
||||
```
|
||||
|
||||
Strings can be concatenated using the `++` operator. Use the built-in function
|
||||
`str` to convert values to strings.
|
||||
|
||||
```talc
|
||||
>> apples = 5
|
||||
5
|
||||
>> "I have " ++ str(apples) ++ " apples"
|
||||
"I have 5 apples"
|
||||
```
|
||||
|
||||
See [the table below](#string-escapes) for a list of all escape sequences.
|
||||
|
||||
## Symbols
|
||||
|
||||
*Symbols* (called *atoms* in some languages) represent interned strings.
|
||||
Symbols are used by default for the keys of [tables](./tables.md), but can also
|
||||
be used for other purposes, such as enumerations. Since symbols are interned,
|
||||
comparing or hashing them is very fast.
|
||||
|
||||
Symbols can be written with a colon followed by any sequence of characters that
|
||||
would form a valid identifier. A string literal may also be used.
|
||||
|
||||
```talc
|
||||
>> :a_symbol
|
||||
:a_symbol
|
||||
>> :"symbol with spaces"
|
||||
:"symbol with spaces"
|
||||
```
|
||||
|
||||
## String escapes
|
||||
|
||||
| Escape code | Result |
|
||||
|-------------|---------------------------------------------------------|
|
||||
| `\'` | Single quote (`'`) |
|
||||
| `\"` | Double quote (`"`) |
|
||||
| `\\` | Backslash (`/`) |
|
||||
| `\0` | Null byte (0x00) |
|
||||
| `\a` | Bell (0x07) |
|
||||
| `\b` | Backspace (0x08) |
|
||||
| `\t` | Tab (0x09) |
|
||||
| `\n` | Newline (0x0A) |
|
||||
| `\v` | Vertical tab (0x0B) |
|
||||
| `\f` | Form feed (0x0C) |
|
||||
| `\r` | Carriage return (0x0D) |
|
||||
| `\e` | Escape (0x1B) |
|
||||
| `\xXX` | An arbitrary byte specified by two hex digits |
|
||||
| `\u{XX..}` | The sequence of UTF-8 bytes for the specified codepoint |
|
||||
|
||||
Examples:
|
||||
|
||||
```talc
|
||||
>> "\x41"
|
||||
"A"
|
||||
>> "\x0A"
|
||||
"\n"
|
||||
>> "\u{1F41D}"
|
||||
"🐝"
|
||||
```
|
55
docs/src/lang/tables.md
Normal file
55
docs/src/lang/tables.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Tables
|
||||
|
||||
While lists associate their items with integer indices, *tables* associate
|
||||
their values with keys of varying type. Tables are written in curly braces,
|
||||
with the key and value separated by an equals sign (`=`).
|
||||
|
||||
```talc
|
||||
>> numbers = { 1="one", 2="two", 55="fifty-five" }
|
||||
{ 2="two", 55="fifty-five", 1="one" }
|
||||
>> numbers[55]
|
||||
"fifty-five"
|
||||
>> numbers[20] = "twenty"
|
||||
"twenty"
|
||||
>> numbers
|
||||
{ 2="two", 1="one", 20="twenty", 55="fifty-five" }
|
||||
```
|
||||
|
||||
The order of elements in a table is unspecified and may even be different
|
||||
between two otherwise identical tables.
|
||||
|
||||
Table keys may be any of the following:
|
||||
|
||||
- Integers (useful for representing sparse lists)
|
||||
- Ratios
|
||||
- Strings
|
||||
- Symbols
|
||||
- Booleans
|
||||
- Nil
|
||||
|
||||
As a special case, if the key is written with an identifier, it will be treated
|
||||
like a symbol. Accessing values with symbol keys can also be done using the
|
||||
dot operator (`.`).
|
||||
|
||||
```talc
|
||||
>> oxygen = { number=8, mass=15.999, symbol="O" }
|
||||
{ mass=15.999, symbol="O", number=8 }
|
||||
>> oxygen[:mass]
|
||||
15.999
|
||||
>> oxygen.number
|
||||
8
|
||||
```
|
||||
|
||||
To use the value of an expression as a key, surround the expression in
|
||||
parentheses. This also allows for keys based on the value of a variable.
|
||||
|
||||
```talc
|
||||
>> a = 12
|
||||
12
|
||||
>> tbl = { a="no parens", (a)="parens" }
|
||||
{ 12="parens", a="no parens" }
|
||||
>> tbl[:a]
|
||||
"no parens"
|
||||
>> tbl[a]
|
||||
"parens"
|
||||
```
|
63
docs/src/lang/variables.md
Normal file
63
docs/src/lang/variables.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Variables and scope
|
||||
|
||||
Values can be assigned to variables for later use using an equals sign:
|
||||
|
||||
```talc
|
||||
>> total = 13.95 + 6.98
|
||||
20.93
|
||||
>> tax = 0.04
|
||||
0.04
|
||||
>> total + total * tax
|
||||
21.7672
|
||||
```
|
||||
|
||||
Variables may contain Unicode; the first character must be an underscore (`_`)
|
||||
or a character in the `XID_Start` character class and subsequent characters
|
||||
must be in the `XID_Continue` class. From ASCII, the former includes lower-
|
||||
and uppercase letters and underscores and the latter additionally includes
|
||||
digits.
|
||||
|
||||
Variables can be reassigned and are dynamically-typed:
|
||||
|
||||
```talc
|
||||
>> x = 5
|
||||
5
|
||||
>> x = x * (3.0 + 1.5i)
|
||||
15.0+7.5i
|
||||
```
|
||||
|
||||
The previous expression can be written more tersely using a compound assignment
|
||||
operator:
|
||||
|
||||
```talc
|
||||
>> x *= 3.0 + 1.5i
|
||||
15.0+7.5i
|
||||
```
|
||||
|
||||
In the REPL, variables at the top level are **global** by default. A variable
|
||||
can be made **local** using the `var` keyword. The values of local variables
|
||||
will not persist between entries to the REPL. Variables in scripts and in
|
||||
inner scopes are local by default and can be made global by using the `global`
|
||||
keyword.
|
||||
|
||||
Talc is lexically scoped. To create a scope, use the `do` and `end` keywords.
|
||||
The REPL will not accept input until all delimiters have been matched, enabling
|
||||
you to write multiline programs.
|
||||
|
||||
```talc
|
||||
>> x = 5
|
||||
5
|
||||
>> do
|
||||
y = 4
|
||||
y += 5
|
||||
x *= y
|
||||
end
|
||||
45
|
||||
>> x
|
||||
45
|
||||
>> y
|
||||
Error: name_error: undefined global y
|
||||
```
|
||||
|
||||
Later we will see other expressions that create scopes, so it is important to
|
||||
understand how they behave.
|
107
docs/theme/highlight.js
vendored
Normal file
107
docs/theme/highlight.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue