aboutsummaryrefslogtreecommitdiff
path: root/TUTORIAL.md
diff options
context:
space:
mode:
Diffstat (limited to 'TUTORIAL.md')
-rw-r--r--TUTORIAL.md201
1 files changed, 97 insertions, 104 deletions
diff --git a/TUTORIAL.md b/TUTORIAL.md
index df2eea7..701839b 100644
--- a/TUTORIAL.md
+++ b/TUTORIAL.md
@@ -3,9 +3,8 @@
Tutorial
========
-This tutorial consists of a language tour
-and a set of exercises, in the order of
-mentioning.
+This tutorial consists of a language tour and a
+set of exercises, in the order of mentioning.
Tour
@@ -15,8 +14,8 @@ Tour
Arithmetic operations
---------------------
-Addition, multiplication, subtraction and division
-are supported with +, *, - and / respectively.
+Addition, multiplication, subtraction and division are
+supported with `+`, `*`, `-` and `/` respectively.
```console
> (+ 1 1)
2 : Int
@@ -28,9 +27,9 @@ are supported with +, *, - and / respectively.
2 : Int
```
-As addition and multiplication are associative,
-multiple arguments can be used (even just one,
-even though that doesn't really make sense):
+As addition and multiplication are associative, multiple
+arguments can be used (even just one, even though that
+doesn't really make sense):
```console
> (+ 1 2 3)
6 : Int
@@ -57,8 +56,8 @@ standard library:
Booleans
--------
-Myslip supports booleans and `and`, `or`, `xor` and `not`
-for their comparisons.
+Myslip supports booleans and `and`, `or`,
+`xor` and `not` for their comparisons.
```console
> true
true : Bool
@@ -74,8 +73,8 @@ false : Bool
false : Bool
```
-If-expressions are provided by the standard library in the
-form `(if [condition] [iftrue] [iffalse])`:
+If-expressions are provided by the standard library
+in the form `(if [condition] [iftrue] [iffalse])`:
```console
> (if true 1 0)
1 : Int
@@ -121,10 +120,9 @@ x saved
> x
1 : Int
```
-The REPL interprets this as `((let x 1) x)`, which you
-could also type but would make a more cumbersome REPLing
-experience (and would make loading definitions from files
-nigh impossible).
+The REPL interprets this as `((let x 1) x)`, which you could
+also type but would make a more cumbersome REPLing experience
+(and would make loading definitions from files nigh impossible).
Shadowing works as expected:
```console
@@ -139,8 +137,8 @@ and after it it is too, while in the middle term where
Types
-----
-Types are written as seen in the return types in the REPL.
-The base types of myslip are
+Types are written as seen in the return types
+in the REPL. The base types of myslip are
* `Int` for integer
* `Bool` for boolean
* `Nil` for `()`
@@ -149,25 +147,25 @@ The base types of myslip are
* `Quote`, `Vector` and `Sum` for use in data structures.
The types used in data structures will be covered later.
-These can be combined using the arrow type, list type and
-vector type.
+These can be combined using the arrow
+type, list type and vector type.
-`(A -> B)` denotes a function with arguments of type `A`
-and a return value of type `B`.
+`(A -> B)` denotes a function with arguments
+of type `A` and a return value of type `B`.
`(A B C D)` denotes a 4-length list with the respective types
-at respective positions. Though if it is an actual list not
-to be interpreted, in most cases a `Quote` will be present in
-the type: `(Quote (A B C D))`. Note that the length of a list
-can be any nonnegative integer (within memory constraints),
-but it needs to be fixed.
+at respective positions. Though if it is an actual list not to
+be interpreted, in most cases a `Quote` will be present in the
+type: `(Quote (A B C D))`. Note that the length of a list can
+be any nonnegative integer (within memory constraints), but it
+needs to be fixed.
`(A ...)` denotes a list the length of which is not known and
whose each element is of type `A`. If this is in a vector
structure, `Vector` is prepended as such: `(Vector (A ...))`.
-`(Sum A B)` denotes the type of a coproduct, the left type of
-which is `A` and right type `B`.
+`(Sum A B)` denotes the type of a coproduct, the
+left type of which is `A` and right type `B`.
Generics have limited support in myslip.
They are written in uppercase.
@@ -177,13 +175,16 @@ Functions
---------
Functions are written in the form of
-`(fn [argument list] [argument type list] [return type] [function body])`.
-They don't have names of themselves, but they can be bound
-using `let`.
-
-The following example features a simple increment function
-and a function for checking if a integer is between two
-others.
+```myslip
+(fn [argument list] [argument type list] [return type]
+ [function body]
+)
+```.
+They don't have names of themselves,
+but they can be bound using `let`.
+
+The following example features a simple increment function and
+a function for checking if a integer is between two others.
```console
> (let ++ (fn a Int Int (+ a 1)))
++ saved
@@ -210,19 +211,16 @@ In principle,
```myslip
(1 2 3 4 5)
```
-is a valid list, but it is evaluated by the interpreter,
-which assumes that the first term, `1`, is an operator.
-That's why constructing a list requires the operator
-`quote`:
+is a valid list, but it is evaluated by the interpreter, which
+assumes that the first term, `1`, is an operator. That's why
+constructing a list requires the operator `quote`:
```console
-> quote
-quote : (T -> (Quote T))
> (quote 1 2 3 4 5)
(quote 1 2 3 4 5) : (Quote (Int Int Int Int Int))
```
-In contrast from many other lisp-variants, in myslip
-sub-expressions are simplified.
+In contrast from many other lisp-variants,
+in myslip sub-expressions are simplified.
```console
> (quote (+ 1 1) (+ 2 2))
(quote 2 4) : (Quote (Int Int))
@@ -231,19 +229,17 @@ sub-expressions are simplified.
The elements of a list can of course be of different types:
```console
> (quote - 0 (quote 1 2))
-(quote - 0 (quote 1 2)) : (Quote ((Int Int) -> Int) Int (Quote (Int Int)))
+(quote - 0 (quote 1 2)) : (Quote (((Int Int) -> Int) Int (Quote (Int Int))))
```
Vectors
-------
-Vectors behave roughly the same as lists, except
-their length is not specified on type-level, and
-their elements can be only of one type.
+Vectors behave roughly the same as lists, except their length
+is not specified on type-level, and their elements can be only
+of one type.
```console
-> vector
-vector : ((T ...) -> (Vector (T ...)))
> (vector 1 2 3 4)
(vector 1 2 3 4) : (Vector (Int ...))
```
@@ -260,32 +256,31 @@ Two vectors can be concatenated using the `<>`-operator:
(vector 1 2 3 4) : (Vector (Int ...))
```
-The standard library provides the function `sum` to
-calculate the sum of a vector of integers. Through
-type conversions, this works for lists too.
+The standard library provides the function `sum` to calculate
+the sum of a vector of integers. Through type conversions,
+this works for lists too.
Coproducts
----------
-Coproducts ("either-or -type") are instantiated with the
-`coprod` operator:
+Coproducts ("either-or -type") are
+instantiated with the `coprod` operator:
```console
> (coprod (+ 1 2) Bool)
(coprod 3 Bool) : (Sum Int Bool)
> (coprod Int +)
(coprod Int +) : (Sum Int ((Int ...) -> Int))
```
-They can be destructured with pattern matching as covered in
-the next section.
+They can be destructured with pattern
+matching as covered in the next section.
Pattern matching
----------------
-Values can be inspected using pattern matching.
-For basic lists, the `case`-operator can be used.
-It's syntax is:
+Values can be inspected using pattern matching. For basic
+lists, the `case`-operator can be used. It's syntax is:
```myslip
(case [condition]
([pattern 1] [value 1])
@@ -293,8 +288,8 @@ It's syntax is:
...)
```
-Just note that every case expression needs to
-have one wildcard pattern, to ensure exhaustiveness.
+Just note that every case expression needs to have
+one wildcard pattern, to ensure exhaustiveness.
Here's a very basic example:
```console
@@ -306,23 +301,22 @@ x saved
1 : Int
```
-The list can be destructured into parts. If there
-is a `..[variable name]` at the end of a pattern,
-it matches the rest of the list.
+The list can be destructured into parts. If there is a
+`..[variable name]` at the end of a pattern, it matches the
+rest of the list.
```console
> (case (quote 1 2 3 4 5) ((h1 h2 ..tail) (+ h1 h2)) ((h ..t) h) (_ 0))
3 : Int
```
-Nesting in pattern matching works fine too.
+Nesting of lists in pattern matching works fine too:
```console
> (case (quote 1 2 (quote 3 4) 5) ((1 2 (quote 3 4) 5) true) (_ false))
true : Bool
```
-Pattern matching can be done on vectors too.
-Just remember that the rest pattern `..r` needs to be at
-the end of the whole pattern.
+Pattern matching can be done on vectors too. Just remember
+that the rest pattern `..r` needs to be at the end of the whole pattern.
```console
> (let myvec (vector 1 2 3 4 5))
myvec saved
@@ -332,13 +326,15 @@ myvec saved
Coproducts are destructured with `inl` and `inr`:
```console
+> (let myprod (coprod 2 Bool))
+myprod saved
> (case myprod ((inl x) x) ((inr b) (if b 1 0)) (_ -1))
2 : Int
> (case myprod ((inl 2) true) (_ false))
true : Bool
```
-Even if when both an `inl` and `inr` arm are supplied,
-a wildcard pattern is required as myslip doesn't feature an
+Even if when both an `inl` and `inr` arm are supplied, a
+wildcard pattern is required as myslip doesn't feature an
exhaustiveness checker. That is the tradeoff for having
nesting:
```console
@@ -353,11 +349,10 @@ fairly trivial, but that won't happen this summer)
General recursion
-----------------
-General recursion in myslip is achieved through the
-fixed point operator `fix`. It works the same as in
-the course materials: it takes a function of type
-`(T -> T) -> (T -> T)` as an argument and uses that
-for recursive calls.
+General recursion in myslip is achieved through the fixed
+point operator `fix`. It works the same as in the course
+materials: it takes a function of type `(T -> T) -> (T -> T)`
+as an argument and uses that for recursive calls.
The factorial function could be implemented as such:
```myslip
@@ -377,12 +372,11 @@ The factorial function could be implemented as such:
Printing
--------
-This is quite a useless feature as the repl already
-echoes all results. But if you fancy, you can print
-anything using the `print` operator, which is
-behaviorally equivalent to Nil as long as its argument
-is valid myslip. For example, with the standard library
-enabled:
+This is quite a useless feature as the repl already echoes
+all results. But if you fancy, you can print anything using
+the `print` operator, which is behaviorally equivalent to Nil
+as long as its argument is valid myslip. For example, with
+the standard library enabled:
```console
> (let x 1)
x saved
@@ -399,8 +393,8 @@ checker look at you weird, the standard library offers
the convenience function `discard`, which takes anything
as arguments and returns nil.
-Here's an example that shows why you might want to use
-discard:
+Here's an example that shows why
+you might want to use discard:
```console
> ((print 1) (print 2))
Type error: invalid operator: '(print 1)'
@@ -411,8 +405,8 @@ found: 'Nil'
2
(quote () ()) : (Quote (Nil Nil))
```
-As you can see, the return type of the latter try at using
-print twice looks horrible.
+As you can see, the return type of the latter
+try at using print twice looks horrible.
```console
> (discard (print 1) (print 2))
1
@@ -426,15 +420,15 @@ Loops
=====
Loops are quite worthless in a functional language, but I
-might get points for them. The standard library provides the
-functions `repeat` and `map-i->i`.
+might get points for them. The standard library provides
+the functions `repeat` and `map-i->i`.
The former one has the syntax
-`(repeat [operation] [number of times])` which quite
-intuitively repeats the given operation the given number of
-times. The operation should be a function that takes an
-integer as an argument and returns Nil, so this function is
-quite useless for anything but printing.
+`(repeat [operation] [number of times])`,
+which quite intuitively repeats the given operation the given
+number of times. The operation should be a function that takes
+an integer as an argument and returns Nil, so this function is
+useless for anything but printing.
```console
> (repeat (fn x Int Nil (print x)) 10)
1
@@ -506,11 +500,11 @@ may want to try out the `--babysteps` feature
Exercise 3: Fibonacci sequence
------------------------------
-Write a function that calculates the n:th fibonacci number,
-when n is given as the sole argument.
+Write a function that calculates the n:th fibonacci
+number, when n is given as the sole argument.
-This should make you familiar with function definitions and
-fixed point recursion.
+This should make you familiar with function
+definitions and fixed point recursion.
Example of desired behaviour:
```console
@@ -532,12 +526,13 @@ This should make you familiar with typing function
definitions that contain generics.
-Exercise 5: Map left / right (integers)
----------------------------------------
+Exercise 5: Left / right or
+---------------------------
-Write functions `map-left` and `map-right` that take a
-coproduct and a function and map the corresponding side of
-the given coproduct using the given function.
+Write functions `left-or` and `right-or` that take a coproduct
+and a default value of the type of the corresponding hand of the
+coproduct, and if the coproduct is of the left type, returns its
+value, otherwise returns the default value.
Note: the solution is not in the same directory as the rest,
but you can find implementations for these in the standard
@@ -545,5 +540,3 @@ library.
This exercise will train your abilities to use generics more
than the last one. You will get familiar with coproducts.
-
-