aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-23 22:36:05 +0300
committerJoel Kronqvist <joel.kronqvist@iki.fi>2025-08-23 22:36:05 +0300
commit1c0645c559d19d9c7ceb1db51d68e052a180709f (patch)
tree857d4295ebeb3e8e8f8050d8b5beac80f2b52ab7
parentef4eb90eac9d99c1f677baca5ddaca2afbc1627f (diff)
downloadmyslip-devel.tar.gz
myslip-devel.zip
doc: added system requirements & fixed map x to x orHEADdevel
-rw-r--r--README.md82
-rw-r--r--TUTORIAL.md201
2 files changed, 149 insertions, 134 deletions
diff --git a/README.md b/README.md
index 3f62d29..11be6ff 100644
--- a/README.md
+++ b/README.md
@@ -4,24 +4,24 @@ myslip README
=============
Below is a short introduction to this programming language
-and instructions on setting it up.
-`TUTORIAL.md` may help getting familiar with the language.
+and instructions on setting it up. `TUTORIAL.md` may help
+getting familiar with the language.
Language introduction
---------------------
Myslip is a functional, symbolically interpreted programming
-language. It's syntax is inspired by lisp and polish
-notation. The author hasn't programmed much in lisp-variants
-or in (non-general-purpose) functional languages, so the
-language might include some slips or oddities, hence
-the name. But the language is coherent within itself,
-so learning it shouldn't be too hard.
+language. It's syntax is inspired by lisp and polish notation.
+The author hasn't programmed much in lisp-variants or in
+(non-general-purpose) functional languages, so the language
+might include some slips or oddities, hence the name. But the
+language is coherent within itself, so learning it shouldn't
+be too hard.
-Valid myslip s-expressions may be atoms of different types
-or lists of them, though not all syntactically valid
-myslip expressions are ones that can be evaluated.
+Valid myslip s-expressions may be atoms of different types or
+lists of them, though not all syntactically valid myslip
+expressions are ones that can be evaluated.
The following is s-expressions explained intuitively in
something that looks a bit like a BNF:
@@ -29,22 +29,20 @@ something that looks a bit like a BNF:
S-expression := Atom | List
Atom := Operator | Value | Variable ...
List := (S-expression ... S-expression)
-```
Don't take it to be exact. For example lists are actually
implemented as linked lists.
-The myslip interpreter performs type checking on
-s-expressions and evaluates them according to polish
-notation, ie. the first S-expression of a list is taken to
-be the operator that is passed the rest of the expressions
-as arguments.
+The myslip interpreter performs type checking on s-expressions
+and evaluates them according to polish notation, ie. the first
+S-expression of a list is taken to be the operator that is
+passed the rest of the expressions as arguments.
Running myslip
--------------
-myslip can be built using cargo 1.88.0. Instructions to
-install cargo can be found online:
+myslip can be built using Cargo versions 1.88.0 and 1.89.0.
+Instructions to install cargo can be found online:
https://doc.rust-lang.org/cargo/getting-started/installation.html
If you are having trouble due to having a different version
@@ -52,21 +50,45 @@ and you used rustup for your cargo installation, you can
follow these instructions on how to change the rust version
https://rust-lang.github.io/rustup/overrides.html
-TODO: system requirements? try it out on debian
-So, for example
+So, for example on some linux systems featuring the `apt`
+package manager, the following works (tested on Debian 13)`:
```console
-$ sudo apt install curl git
+$ sudo apt install curl git builb-essential
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+$ . "$HOME/.cargo/env"
$ git clone 'https://git.cron4.fi/myslip.git'
$ cd myslip
```
-and then myslip can be accessed either via `cargo run`,
-or alternatively you can add it to your `$PATH`:
+and then myslip can be accessed either via `cargo run`, or
+alternatively you can add it to your `$PATH`:
```console
$ cargo build
+$ mkdir -p ~/.local/bin
+$ export PATH="$PATH:~/.local/bin"
+$ echo 'export PATH="$PATH:~/.local/bin"' >> ~/.bashrc
+$ ln "$(pwd)/target/debug/myslip" ~/.local/bin/myslip
+$ myslip
+```
+
+Installation has been tested on Aalto SSH servers in addition
+to debian/13 in case you prefer that. Here is how to install
+and compile the project there:
+```console
+$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+$ ~/.cargo/bin/cargo --version
+$ git clone 'https://git.cron4.fi/myslip.git'
+$ cd myslip/
+$ ~/.cargo/bin/cargo build
+$ mkdir -p ~/.local/bin
$ ln "$(pwd)/target/debug/myslip" ~/.local/bin/myslip
+$ export PATH="$PATH:~/.local/bin"
$ myslip
```
+Of course you must update your path next time when you open
+your shell too, so you might want to add
+`export PATH=$PATH:~/.local/bin` to your `~/.bashrc` in case
+you don't have a personal preference on how to manage your
+`$PATH` and other environment variables.
Exit the REPL by pressing CTRL+C, CTRL+D or entering "exit".
@@ -79,15 +101,15 @@ Running `myslip filename.slip` tries to read a file named
`filename.slip` as an s-expression and evaluates it.
On the other hand, running `myslip` without specifying an
-executable file opens a REPL, in which you can enter
-one s-expression per line for evaluation. Variables bound
-in earlier expressions can be used.
+executable file opens a REPL, in which you can enter one
+s-expression per line for evaluation. Variables bound in
+earlier expressions can be used.
If you wish to load a set of definitions from a file, say
`header.slip`, use the `--load`-argument (`-l` for short):
```console
$ myslip -l header.slip
```
-The standard library, found in `stdlib.slip`, is loaded
-in an equivalent way by default. If you wish to disable
-it, you can use the option `--no-stdlib`.
+The standard library, found in `stdlib.slip`, is loaded in an
+equivalent way by default. If you wish to disable it, you can
+use the option `--no-stdlib`.
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.
-
-