diff options
Diffstat (limited to 'TUTORIAL.md')
-rw-r--r-- | TUTORIAL.md | 201 |
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. - - |