packages feed

MicroHs-0.16.0.0: README.md

# Micro Haskell
This repository contains an implementation of an extended subset of Haskell.
It uses combinators for the runtime execution.

[Try it in your browser](https://augustss.github.io/MicroHs/web-mhs/)

The runtime system has minimal dependencies, and can be compiled even for micro-controllers.
The `boards/` directory contains some samples, e.g., some sample code for an STM32F407G-DISC1 board.

The compiler can compile itself.

## Presentation
You can find my [presentation from the Haskell Symposium 2024](https://docs.google.com/presentation/d/1WsSiSwypNVTm0oZ3spRYF8gA59wyteOsIkPRjCUAZec/edit?usp=sharing), [video](https://m.youtube.com/watch?v=uMurx1a6Zck&t=36m).
There is also a short paper at [`doc/hs2024.pdf`](https://github.com/augustss/MicroHs/blob/master/doc/hs2024.pdf).

## Compiling MicroHs
There are two different ways to compile MicroHs:
* Using GHC. `Makefile` target `bin/gmhs`
* Using the included combinator file and runtime.  `Makefile` target `bin/mhs`

These different ways of compiling need slightly different imports etc.
This happens by GHC looking in the `ghc/` subdirectory first for any extras/overrides.

Compiling MicroHs is really best done using `make`, but there is also a `MicroHs.cabal` file
for use with `cabal`/`mcabal`.  This only builds what corresponds to the first target.
Doing `cabal install` will install the compiler.
Note that `mhs` built with ghc does not have all the functionality.

Also note that there is no need to have a Haskell compiler to run MicroHs.
All you need is a C compiler, and MicroHs can bootstrap, given the included combinator file.

To install `mhs` use `make minstall`.  This will install `mhs` in `~/.mcabal` in the same
way as `mcabal` (MicroCabal) would have.  It will install a compiler binary and a compiled base package.
You will have to add `~/.mcabal/bin` to your `PATH`.

Alternatively, to install `mhs` use `make oldinstall`.  By default this copies the files to `/usr/local`,
but this can be overridden by `make PREFIX=dir oldinstall`.
You also need to set the environment variable `MHSDIR`.

To compile on Windows make sure `cl` is in the path, and then use `nmake` with `Makefile.windows`.

The compiler can also be used with emscripten to produce JavaScript/WASM.

### Using GMP for `Integer`
The default implementation of the `Integer` type is written in Haskell and is quite slow.
It is possible to use the [GMP](https://gmplib.org/) library instead.
To use GMP you need to uncomment the first few lines in the `Makefile`, and also
modify the definition that directs the C compiler where to find GMP.

***NOTE*** To switch between using and not using GMP you need to do `make clean`.
You might also need to do `make USECPPHS=cpphs bootstrapcpphs` if there are complaints.

## Example
The file `Example.hs` contains the following:
```Haskell
module Example(main) where

fac :: Int -> Int
fac 0 = 1
fac n = n * fac(n-1)

main :: IO ()
main = do
  let rs = map fac [1,2,3,10]
  putStrLn "Some factorials"
  print rs
```

First, make sure the compiler is built by doing `make`.
Then compile the file by `bin/mhs Example -oEx` which produces `Ex`.
Finally, run the binary file by `./Ex`.
This should produce
```
Some factorials
[1,2,6,3628800]
```

## Libraries
The `Prelude` contains the functions from the Haskell Report and a few extensions,
with the notable exception that `Foldable` and `Traversable` are not part of the `Prelude`.
They can be imported separately, though.

### Not importing `Prelude`
To completely avoid importing the prelude (which can be needed in base to
avoid circular imports) use the incantation `import qualified Prelude()`.
This will not even try to open `Prelude.hs`.  It also avoids the automagic
(qualified) import of `Mhs.Builtin` that normally happens.


## Interactive mode
If no module name is given the compiler enters interactive mode.
You can enter expressions to be evaluated, or top level definitions (including `import`).
Simple line editing is available.

## MHS as a cross compiler
When `mhs` is built, targets.conf is generated. It will look something like this:
```ini
[default]
cc = "cc"
conf = "unix-64"
```

You can add other targets to this file, changing which compiler command is used and which runtime is
selected and then use the `-t` argument to select which target you would like.

## Files
There is a number of subdirectories:
* `Tools/` a few useful tools for compressions etc.
* `bin/` executables are put here
* `generated/` this contains the (machine generated) combinator file for the compiler.
* `lib/` this contains the `Prelude` and other base library file.
* `src/MicroHs/` the compiler source
* `src/runtime/` the runtime source
* `tests/` some tests

# Preprocessor
Sadly, compiling a lot of Haskell packages needs the C preprocessor.
To this end, the distribution contains the combinator code for `cpphs`.
Doing `make bin/cpphs` will create the binary for the preprocessor.

To bootstrap `cpphs` you can do `make bootstrapcpphs`.
This assumes that you have `git` to download the needed packages.
At the moment, the downloaded packages are forks of the original to
make it compile with `mhs`.

To identify that it is MicroHs that is the compiler it defines the symbol `__MHS__`.

# Contributing
Contributions are very welcome!

When modifying the compiler, run `make newmhs` or `make newmhsz` (the latter compresses the binary)
to generate a compiler that includes your changes.

## Libraries

The libraries live in the `lib/` directory. Adding missing functions/instances/types from the report is a welcome contribution.
Common things from `base` and GHC boot libraries that use a lot of GHC-specific code (such as `array`, `bytestring`, `text`, ...) can also be added.

## Tests

The test suite is located in the `tests/` directory.

To add a new test, create a `MyTest.hs` file and a corresponding `MyTest.ref` file for the expected output.
Then add it to the `test` rule in `tests/Makefile`:
```makefile
	$(TMHS) MyTest     && $(EVAL) > MyTest.out     && diff MyTest.ref MyTest.out
```

If you want to test that a module fails to compile with a certain error message,
add it to `tests/errmsg.test`, for example:
```
module E() where
x :: Int
x = y
-----
"../tmp/E.hs": line 4, col 5: undefined value: y

=====
```

To run the test suite, do
* `make runtest` to use the GHC-compiled compiler
* `make runtestmhs` to use the MicroHs-compiled compiler
* `make runtestemscripten` to use the MicroHs-compiled compiler targeting JavaScript

## Primitives

If you want to add a new primitive, you need to modify a few things:
* in `src/runtime/eval.c`
  - add a variant to `enum node_tag`
  - add an entry to the `primops` table (mapping the name of your primitive to the tag)
  - add a `case` in `printrec`
  - implement the primitive by adding a `case` in `evali` (you can use the other primitives as a guide)
* in `src/MicroHs/Translate.hs`
  - add an entry to the `primTable`, to make the primitive available in the interactive mode
* in `ghc/PrimTable.hs`
  - add an entry to `primOps`, if the primitive should be available in the GHC-compiled interactive mode
* in `hugs/PrimTable.hs`
  - add an entry to `primOps`, if the primitive should be available in the Hugs-compiled interactive mode

Then you can use the primitive via the `_primitive` keyword (`_primitive "myPrimitive"`).

# Thank You
A big thanks goes to the people who have contributed to MicroHs:
@amigalemming
@arossato
@benclifford
@claudeha
@dmjio
gay@disroot.org
@gergoerdi
@ikervagyok
@jmaessen
@juhp
@kolmodin
@konsumlamm
@liolin
@lortabac
@MaximilianAlgehed
@meooow25
@philderbeast
@rewbert
@sol
@Superstar64
@thielema
@thimc
@thma
@treeowl
@TristanCacqueray
@tvmaaren
@yobson


# FAQ
*
  * Q: When will it get _insert feature_?
  * A: Maybe some time, maybe never.  But it doesn't hurt to ask for it.
*
  * Q: Why are the error messages so bad?
  * A: Error messages are boring.

---

For more information, see the [wiki](https://github.com/augustss/MicroHs/wiki).

---

# Finding modules *NOT YET IMPLEMENTED*
A module `M` is located using the _sourcePath_ and the _packageDbPath_.
Both of the paths are a list of directories and are searched left-to-right.
This lookup is used both `import` and modules given on the command line.

Note: If the module name given on the command line has suffix `.hs` or `.lhs`
it is used as a file name, rather than a module name.

First, the the _sourcePath_ is used.  For each directory in the
path:
 * the module name `M` is appended with `.` changed to `/`.
 * then the suffixes `.hs`, `.hsc`, and `.lhs` are tried in order
 * if the file exists it is assumed to be the source for module `M`

Second, if no source file is found, then each directory in the
_packageDbPath_ is tried.  If the module is found, the corresponing
package is loaded and the compiled module 'M' from that package is used.

## Setting the _sourcePath_
The default _sourcePath_ is just the current directory, `.`.
The path can be cleared by using the `-i` command line flag.
To append to the path use `-iPATH`, where `PATH` is a colon (`:`)
separated list of directories.

## Setting the _packageDbPath_
The default _packageDbPath_ is take from the `mhs.conf` file
in the section `[mhs]` and key `packageDbPath`.
The path can contain environment variables that are expanded.
In addition $MHSPKG expand to the package directory relative to the executing binary.
Furthermore $VERSION expands to the mhs version number.

The path can be cleared by using the `-a` command line flag.
To append to the path use `-aPATH`, where `PATH` is a colon (':')
separated list if directories.

## Installing packages

The _packageDb_ directory can be given directly with the `-Q`
flag used to install.

The `mcabal` command can install to a particular package db by using
`--install=PATH`.