• Stars
    star
    119
  • Rank 297,930 (Top 6 %)
  • Language
    Haskell
  • License
    MIT License
  • Created about 4 years ago
  • Updated almost 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Trying to write an understandable implementation of Haskell, in Haskell

Haskell In Haskell

This is my attempt at writing an understandable implementation of a subset of Haskell, in Haskell itself.

Usage

This project can be built with cabal build, or installed with cabal install. Installation should put an executable named haskell-in-haskell on your path. Otherwise, you can run the project directly with cabal run haskell-in-haskell --, followed by the arguments you'd like to pass.

Compiling

To compile a Haskell file, just run:

haskell-in-haskell compile in.hs out.c

in.hs is the Haskell input file, and out.c is the C code to generate.

The compiler only works with single Haskell files. To run the generated code, you'll need to have a C compiler handy, and to make sure that the runtime.c file is in the same directory, before running:

gcc -std=c99 out.c

(Replacing gcc by your C compiler of choice)

The C generated should conform to the C99 standard. You can also pass -DDEBUG to C compiler, which will enable some debug printing. This will print out some Garbage Collection information, and a "stack trace" of program execution:

hs__entry
indirection_entry
hs_main
indirection_entry
hs_foo
hs__S_add
hs_foo__S__S_2
hs_increment
hs_foo__S__S_2__S__S_3
hs_increment_case_0
GC Done. 0x00040 ↓ 0x00040 ↑ 0x000C0
hs__S_add
hs_foo_x
hs__S_add_case_0
hs_increment_case_0__S__S_0
hs__S_add_case_0_case_0
hs__S_add_case_0
hs_foo_x
hs__S_add_case_0_case_0
hs__entry_case_0

Stages

You can also see the compiler's output after various stages, so:

This will print the tokens after running the Lexer stage

haskell-in-haskell lex in.hs

This will print the parsed AST:

haskell-in-haskell parse in.hs

This will print the simplified AST:

haskell-in-haskell simplify in.hs

This will print the AST after type-checking:

haskell-in-haskell type in.hs

This will print the "STG" for your code, which is an intermediate functional IR:

haskell-in-haskell stg in.hs

Finally, this will print the "CMM", which is the last stage before generating C code:

haskell-in-haskell cmm in.hs

Features

The first big missing thing is IO. The way main works in this version of Haskell is that it must either be main :: Int, or main :: String, and the program evaluates main before printing out its value.

In terms of features we have:

Your standard top level definitions and bindings:

x :: Int
x = 33

y :: String
y = 4

z :: Int -> Int
z 3 = 0
z _ = 4

We have let expressions:

x =
  let z = 3
      y = 4
  in z + y

As well as where expressions:

x = z + y
  where
    z = 3
    y = 4

Your standard arithmetic operators:

x = 1 + 3 / 45 * 6 - 34

Strings, and concatenation:

x = "foo" ++ "bar"

Booleans:

true :: Bool
true = True

false :: Bool
false = False

z :: Bool
z = 3 > 4

If expressions:

x = if 1 > 2 then 3 else 5

Case expressions:

case z of
  1 -> 3
  x -> x
  _ -> 4
  
case x of
  "foo" -> "bar"
  _ -> "baz"

This extends to your standard multiple function heads:

add 0 0 = 0
add n 0 = n
add n m = add n (m - 1)

We have polymorphic functions:

id :: a -> a
id x = x

As well as your standard polymorphic ADTs:

data List a = Cons a (List a) | Nil

length :: List a -> Int
length Nil = 0
length (Cons _ rest) = 1 + length rest

Finally, we have type synonyms, which can't be polymorphic:

type ListInt = List X

type X = Int

Everything beyond that has not been implemented. I'd say this is a respectable chunk of Haskell 98, but some glaring omissions include IO, modules, and typeclasses, as well as the entire standard library.

Implementation Features

In terms of the implementation, this is based of the 1992 STG paper, so we have lazy evaluation, garbage collection, and updates, to avoid evaluating closures twice.

Examples

The /examples directory is a bit poor, but the /integration_tests directory should have a few more examples of things accepted by the compiler.

Contributing

If you want to help fix a bug, a first recommendation is to use the following compilation options for your C output:

gcc -DDEBUG -g -fsanitize=address  -fsanitize=undefined -std=c99 .output.c                                                              

This will enable asan and ubsan, which provide runtime checks against common errors with C. This is immensely useful in catching bad usage of memory as early as possible.

This is the source of most bugs in the compiler.

Tests

There are two forms of tests. Some stages have basic tests, which can be run with

cabal test

but these mainly cover the frontend of the compiler.

A more extensive suite of tests can be run with:

python3 integration_tests.py

This script will go over all the Haskell files in integration_tests/, and run the full compiler over them, and then run gcc over the outputted C, and then run the resulting executable, making sure that the output matches the expected results.

For this to work, you need to have gcc available, along with ubsan and asan. These are used in order to detect memory issues early in the tests.

This suite is slower, but much more effective at finding problems.

Resources

I'm currently writing a series going through the implementation of this compiler in depth, so I'd recommend looking through that if you want to understand more.

https://www.microsoft.com/en-us/research/wp-content/uploads/1992/04/spineless-tagless-gmachine.pdf https://homepages.inf.ed.ac.uk/wadler/papers/pattern/pattern.pdf http://moscova.inria.fr/~maranget/papers/ml05e-maranget.pdf

More Repositories

1

alchemy

A discord library for Elixir
Elixir
157
star
2

haze

A bittorrent client, for learning purposes
Haskell
106
star
3

saferith

Constant time big numbers for Go
Go
97
star
4

cait-sith

Threshold ECDSA via Triples
Rust
72
star
5

seed-split

Splitting seed phrases into shares
Rust
63
star
6

boo-hoo

An implementation of ZKBoo
Rust
33
star
7

yao-gc

A basic implementation of Yao's Garbled Circuits
Rust
30
star
8

ludus

A pluggable NES emulator
Rust
29
star
9

multiset-hash

A small crate for hashing multi sets
Rust
14
star
10

magikitten

Easy Fiat-Shamirization using Meow
Rust
13
star
11

meow

Rust
13
star
12

deevee

Designatived verifier Schnorr signatures
Rust
13
star
13

poline

Tiny language with green threads
Rust
10
star
14

persistent-ts

Persistent data structures for Typescript
TypeScript
9
star
15

nimotsu

Rolling some crypto for PGP-esque public key message sending
Rust
9
star
16

kyokusen

Elliptic Curves for Cryptography
Go
9
star
17

viviani

Elixir
8
star
18

cauchy

A hardware accelerated complex function plotter
Rust
7
star
19

bittrickle

UDP bittorrent tracker
Rust
7
star
20

Rem-Boo

Fast ZK proofs over boolean circuits with RAM
Rust
6
star
21

ginkou

Japanese sentence bank program. Add and find sentences for language learning.
Rust
6
star
22

nuntius

Having fun making an E2E messaging app
Go
6
star
23

serve-csv

Create a web API from static csv files
Go
5
star
24

raymarch

Rust
5
star
25

populate

Populate a music library based on a descriptive file
Haskell
5
star
26

hax

A bullet hell game in haskell
Haskell
4
star
27

arbor

A rusty replacement for the `tree` command
Rust
4
star
28

nicer-mecab

Japanese morphological analysis. Wrapper over mecab.
Rust
4
star
29

polka

A C compiler, using the most advanced version of Scala
Scala
4
star
30

eddo

Playing around with Ed25519 signatures
Rust
4
star
31

Advent-2018

Haskell
4
star
32

ovis

Simple functional programming language
Rust
4
star
33

chika

A low level procedural language, compiling to assembly
Rust
4
star
34

iku

WIP programming language
Rust
3
star
35

typhoon

A decent bittorrent library and program
Rust
3
star
36

advent

Advent of code solutions
Haskell
3
star
37

ludus-emu

An NES emulator using the ludus crate
Rust
3
star
38

haisou-chan

A library for simulating network delays
Rust
3
star
39

modular-protocol-security-paper

TeX
3
star
40

peerbin

Peer based code sharing site
JavaScript
3
star
41

strix

Rust
2
star
42

alchaline

Elixir
2
star
43

delay-coin

Playing around with a cryptocurrency based on verifiable delay functions.
Rust
2
star
44

Kirbot-1.5

A simple discord bot, written in python
Python
2
star
45

dex

Pokedex viewing app
JavaScript
2
star
46

talks

TypeScript
2
star
47

sally

Learning how to make a basic shell in C
C
2
star
48

mpc-for-group-reconstruction-circuits

TeX
2
star
49

butterfly-test

Testing an algorithm for creating routing networks from permutations
Jupyter Notebook
2
star
50

big-boo

Experimenting with fast symmetric ZK proofs of knowledge
Rust
2
star
51

katex-playground

Play around with katex in your browser!
TypeScript
2
star
52

toy-stark

A toy implementation of the STARK protocol
Rust
2
star
53

wordle

Playing around with the infamous word game hit of 2022
Rust
2
star
54

mariner

An experiment in ZK circuit DSLs
Rust
2
star
55

omocha

A toy blockchain
Rust
2
star
56

solopong

A simple pong game
TypeScript
1
star
57

lambdabot

Elixir
1
star
58

chess

TypeScript
1
star
59

conway

Playing around with Conway's game of life
Haskell
1
star
60

alg-intro-exercises

C++
1
star
61

ripple

Decentralised IRC-like service
Go
1
star
62

huffman-rs

An implementation of Huffman coding
Rust
1
star
63

ludus-web

Seeing if I can get my NES emulator to work through WASM
HTML
1
star
64

micro-ecs

A small ecs framework for TypeScript
TypeScript
1
star
65

CSES

Solutions to https://cses.fi/problemset/
C++
1
star
66

musync

Configuration based music syncing
Go
1
star
67

srhub

Elixir
1
star
68

aldash

Elixir
1
star
69

on-security-against-time-traveling-adversaries

TeX
1
star
70

bridger

Elixir
1
star
71

kirbot

Elixir
1
star
72

hirch

Haskell
1
star
73

web-craft

WebGL voxel game
TypeScript
1
star
74

reg-viz

Visualizing Regular Expressions
Haskell
1
star
75

disco-old

Haskell
1
star
76

advent-2022

Rust
1
star
77

scroll

Little dungeon crawler
TypeScript
1
star
78

parcel-ts-react-demo

An example of using Typescript & React with Parcel
TypeScript
1
star
79

wahlbergdown

Silly language for the https://github.com/langjam/jam0001
Rust
1
star
80

cici

A self-hosting C compiler
C
1
star
81

ck-dodo

Double odd curve(s)
Rust
1
star