A lisp
REPL interpreter made in Haskell
.
- Numbers (
Float
) - Addition (
+
) - Subtraction (
-
) - Booleans (
true
,false
) - Comparison operators (
=
,>
,<
,>=
,<=
) - def
- if
- lambdas
Just run:
docker build . -t hisp
docker run -it hisp
Observation: the build tools of Haskell themselves seem to be very heavy, I've got a 1GB Docker image on my computer just with a 3 line Dockerfile π¨
hisp
can be compiled/executed using either using stack
or just by using ghc
.
You will need stack
installed on your computer, which is a tool for developing Haskell
projects.
To compile and run:
stack run
You will need ghc
installed on your computer, which is the Haskell
compiler.
This repository has a shell script (already with chmod +x
, to run like a binary) called compile_and_run.sh
. Just run it like this:
./compile_and_run.sh
Since hisp
is built with stack
, the folders follow the standard of it.
hisp
β README.md
β ...
ββββ app
β ββββ Main.hs
ββββ src
β ββββ ...
ββββ test
ββββ ...
- The
app
folder contains themain
function that starts the REPL. - The
src
folder contains the code that is consumed by themain
function, so it is much like a library folder. - The
test
folder, well, as the name suggests, it has the code for the tests.
Tests are run using stack
, you should install it first. To run them, just use:
stack test
To run the linter, you will have to install first hlint
. To check if everything is correct:
hlint .
Well it has 3 main steps, like many interpreters:
Considering someone wants to see the result of the following lisp
code:
First we take it as raw input (String
) and divide it into tokens, which is a list of values ([String]
):
Now that we have those tokens
, we can convert them to something meaningful to us, that we can interpret.
enum Expression {
Symbol(String),
Number(Float),
List([Expression])
Function(([Expression]) -> Expression),
}
The code above is a pseudocode with a Rust
-like syntax. The idea is that you can have a value that is either a Symbol
(holding a String), a Number
(holding a Float), a List
(holding a list of Expression
) or a Function
(holding a function that maps a list of Expression
to a single Expression
).
let four = Expression::Number(4.0);
let plus_sign = Expression::Symbol("+");
After we have the values that represent the code we need to execute, we will interpret it!
To actually get to that 5.0
in the end, we must have somewhere defined that +
receives a bunch of Number
s and then sum them.
We could have an Environment
that contains the standard functions/operators.
struct Environment {
data: HashMap<String, Expression>// map of keys and values
}
Imagine this like a class
that has a map of things like +
, -
, =
, ... to values like Expression::Function(implementation)
.
function sum_implementation (values) {
return values.reduce((acc, curr) => acc + curr, 0)
}
environment = {
"+": sum_implementation,
"-": subtract_implementation,
...
}
Above there is a JSON/JavaScript-like visualization.
That is it! It was just an overview, but you can see all of this on this repository, just a bit more complex to make things like def
s, if
s and lambda
s available to the language.
If you really want to understand more, you can follow some tutorials that are below π
This project is heavly inspired by:
Also, I don't really know Haskell
well, so the code probably could be a lot better. I did my best with what I know about the language at the time.
You can check out the full license here
This project is licensed under the terms of the WTFPL license. You just DO WHAT THE FUCK YOU WANT TO.