Gabriella439 / Gabriella439/Haskell-Morte-Library

Ways to contribute to Morte

Open
#5 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Haskell
Stars
384
Forks
25
PR merge metrics
No merged PRs in 30d

Description

Some people have asked me about some ways to contribute so I'm listing them here in case other people are interested in contributing to Morte, too.

The main ways to contribute are:
- [ ] Add a test suite
- [x] Add a benchmark suite
- [ ] Create a Haskell or LLVM backend
- [ ] Create a Haskell-like front-end
- [ ] Improve performance of normalization and type-checking

Here is a big dump of some of my thoughts on each specific point:
# Add a test suite

A good starting point would be to create one test per example in `Morte.Tutorial` and then some quick-check examples that verify things like:
- `normalize` is idempotent
- If an expression type-checks, then the normalized form still type-checks

Quickcheck tests used to be harder to do for Morte because of the issue of how to generate variable names, but now that Morte supports DeBruijn indices this is easier.
# Add a benchmark suite

A good starting point is the `recursive.mt` example from the tutorial, which is expensive to normalize (almost a second on my machine)
# Create a Haskell backend

The simplest approach is to treat Morte as essentially a subset of Haskell (if you ignore the dependent types functionality) and you can compile Morte to a single Haskell expression that can either:

a) be embedded within a Haskell program, or:
b) compiled to an executable (if the expression has type `IO ()`)

The non-trivial parts are:
- Parametrizing `typeOf`/`typeWith` on `rules`:

The reason why is that you need type-check the final normalized expression with [this rule](https://github.com/Gabriel439/Haskell-Morte-Library/blob/master/src/Morte/Core.hs#L175) deleted in order to enforce that the expression you compile can be translated to Haskell. That particular rule needs to be deleted because it's the one that permits dependent types, which Haskell does not fully support. It's okay if the initial input expression has dependent types, but they have to disappear by the time the expression is normalized.
- Creating a Haskell FFI

Normally this would just involve adding every FFI-imported type/function/literal as just another lambda-bound value. Here are some examples:

```
-- FFI types
\(U : *) -- `()`, the type
-> \(Unit : U) -- `()`, the data
-> \(String : *)
-> \(Int : *)
-> \(IO : * -> *)
-- FFI functions
-> \((>>=) : forall (a : *) -> forall (b : *) -> IO a -> (a -> IO b) -> IO b)
-> \(return : forall (a : *) -> a -> IO a)
-> \(putStrLn : String -> IO U)
-> \(getLine : IO String)
-> \((+) : Int -> Int -> Int)
-> \((*) : Int -> Int -> Int)
-- FFI values/literals
-> \(int0 : Int)
-> \(int1 : Int)
-> \(str0 : String)
-> \(str1 : String)
-> ...
```

The mapping between Morte's lambda-bound types/functions/literals and their equivalent Haskell names needs to be supplied out-of-band.
# Create an LLVM backend

All the challenges of the above Haskell backend apply plus the additional challenge of compiling a functional language to LLVM. I'm not an expert on this so I don't know how difficult it would be.
# Create a Haskell-like front-end

I'm already working on one such front-end here:

https://github.com/Gabriel439/Haskell-Annah-Library

It's still very rough and incomplete. Any other front-ends are also welcome.
# Improve performance of normalization and type-checking

One of the ways you can improve the performance of Morte is to just add two fields to every constructor of the `Expr` type: one for the normalized form of the expression and one for the inferred type. If you instantiated these fields lazily then they could be cached and reused in order to avoid duplicate computation.

This would be a more invasive change to the compiler.

Contributor guide

No contributing guide indexed for this repository

Research direction

Choose one unchecked contribution area before starting, since this issue combines tests, backends, front-ends, and compiler performance work. For tests, begin with the examples in Morte.Tutorial; for backend work, read src/Morte/Core.hs and the type-checking rule mentioned there; for benchmarking, use recursive.mt. Done requires a separately defined scope and validation for the selected area.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
compilers, performance, testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
18/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.