Skip to content

Commit

Permalink
Add the Effekt language (effect-handlers#52)
Browse files Browse the repository at this point in the history
Add the Effekt language
  • Loading branch information
phischu authored Oct 11, 2023
1 parent adeb6c7 commit 6845589
Show file tree
Hide file tree
Showing 14 changed files with 588 additions and 13 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/system_effekt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Effekt

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

#From https://docs.github.com/en/actions/guides/publishing-docker-images
jobs:
bench-system-effekt:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v2

- uses: satackey/[email protected]
# Ignore the failure of a step and avoid terminating the job.
continue-on-error: true

- name: Add write permission to directories
run: |
find . -type d -exec chmod 777 {} \;
- name: Test Effekt system
run: |
make test_effekt
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ test_eff: system_eff
docker run -v $(shell pwd):/source $(DOCKERHUB):eff \
make -C /source/benchmarks/eff test

# Effekt
system_effekt:
docker build -t $(DOCKERHUB):effekt systems/effekt

bench_effekt: system_effekt
docker run -it --init -v $(shell pwd):/source $(DOCKERHUB):effekt \
make -C /source/benchmarks/effekt

test_effekt: system_effekt
docker run -v $(shell pwd):/source $(DOCKERHUB):effekt \
make -C /source/benchmarks/effekt test

# Handlers in Action
system_hia:
docker build -t $(DOCKERHUB):hia systems/hia
Expand Down
39 changes: 26 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,34 @@ $ make bench_ocaml
runs the OCaml benchmarks and produces `benchmarks/ocaml/results.csv` which
contains the results of running the Multicore OCaml benchmarks.

## System availability

| System | Availability |
|--------|--------------|
| [Eff](https://github.com/matijapretnar/eff) | [![Eff](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_eff.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_eff.yml) |
| [Effekt](https://github.com/effekt-lang/effekt) | [![Effekt](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_effekt.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_effekt.yml) |
| [Handlers in Action](https://github.com/slindley/effect-handlers) | [![Handlers in Action](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_hia.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_hia.yml) |
| [Koka](https://github.com/koka-lang/koka) | [![Koka](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_koka.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_koka.yml) |
| [libhandler](https://github.com/koka-lang/libhandler) | [![libhandler](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libhandler.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libhandler.yml) |
| [libmpeff](https://github.com/koka-lang/libmprompt) | [![libmpeff](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libmpeff.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libmpeff.yml) |
| [Links](https://github.com/links-lang/links) | [![Links](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_links.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_links.yml) |
| [Multicore OCaml](https://github.com/ocaml-multicore/ocaml-multicore) | [![Multicore OCaml](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_ocaml.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_ocaml.yml) |

## Benchmark availability

| | [Eff](https://github.com/matijapretnar/eff)<br><br>[![Eff](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_eff.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_eff.yml) | [Handlers in Action](https://github.com/slindley/effect-handlers)<br>[![Handlers in Action](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_hia.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_hia.yml) | [Koka](https://github.com/koka-lang/koka)<br><br>[![Koka](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_koka.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_koka.yml) | [libhandler](https://github.com/koka-lang/libhandler)<br><br>[![libhandler](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libhandler.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libhandler.yml) | [libmpeff](https://github.com/koka-lang/libmprompt)<br><br>[![libmpeff](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libmpeff.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_libmpeff.yml) | [Links](https://github.com/links-lang/links)<br><br>[![Links](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_links.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_links.yml) | [Multicore OCaml](https://github.com/ocaml-multicore/ocaml-multicore)<br>[![Multicore OCaml](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_ocaml.yml/badge.svg)](https://github.com/effect-handlers/effect-handlers-bench/actions/workflows/system_ocaml.yml) |
| :----------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
| **Countdown** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Fibonacci Recursive** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Product Early** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Iterator** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Nqueens** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Generator** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Tree explore** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Triples** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Resume Nontail** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Handler Sieve** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| **Parsing Dollars** | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | :x: | :x: | :heavy_check_mark: |
| | Eff | Effekt | Handlers in Action | Koka | Multicore OCaml |
| :---------------------- | :----------------: | :----------------: | :----------------: | :----------------: | :----------------: |
| **Countdown** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Fibonacci Recursive** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Product Early** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Iterator** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Nqueens** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| **Generator** | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| **Tree explore** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Triples** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Parsing Dollars** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Resume Nontail** | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| **Handler Sieve** | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |

Legend:

Expand Down
40 changes: 40 additions & 0 deletions benchmarks/effekt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
bench: build
hyperfine --export-csv results.csv \
'countdown/main 200000000' \
'fibonacci_recursive/main 42' \
'product_early/main 100000' \
'iterator/main 40000000' \
'nqueens/main 12' \
'tree_explore/main 16' \
'triples/main 300' \
'parsing_dollars/main 20000' \
'resume_nontail/main 20000'

test: build
cd countdown ; ./main 5 > actual ; echo 0 > expected ; diff expected actual
cd fibonacci_recursive ; ./main 5 > actual ; echo 5 > expected ; diff expected actual
cd product_early ; ./main 5 > actual ; echo 0 > expected ; diff expected actual
cd iterator ; ./main 5 > actual ; echo 15 > expected ; diff expected actual
cd nqueens ; ./main 5 > actual ; echo 10 > expected ; diff expected actual
cd tree_explore ; ./main 5 > actual ; echo 946 > expected ; diff expected actual
cd triples ; ./main 10 > actual ; echo 779312 > expected ; diff expected actual
cd parsing_dollars ; ./main 10 > actual ; echo 55 > expected ; diff expected actual
cd resume_nontail ; ./main 5 > actual ; echo 37 > expected ; diff expected actual

build:
cd countdown ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd fibonacci_recursive ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd product_early ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd iterator ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd nqueens ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd tree_explore ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd triples ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd parsing_dollars ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml
cd resume_nontail ; effekt.sh --backend ml --compile main.effekt ; mlton -default-type int64 -output main out/main.sml

clean:
-rm -r */out/
-rm */main
-rm results.csv
-rm */expected
-rm */actual
31 changes: 31 additions & 0 deletions benchmarks/effekt/countdown/main.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import immutable/list
import immutable/option
import io/args
import text/string

effect Get() : Int
effect Set(i: Int): Unit

def countdown(): Int / {Get, Set} = {
val i = do Get();
if (i == 0) {
i
} else {
do Set(i - 1);
countdown()
}
}

def run(n: Int) = {
var s = n;
try {
countdown()
} with Get { () => resume(s)
} with Set { (i: Int) => s = i; resume(()) }
}

def main() = {
val n = commandLineArgs().headOption.getOrElse { "" }.toInt.getOrElse { 5 };
val r = run(n);
println(r)
}
19 changes: 19 additions & 0 deletions benchmarks/effekt/fibonacci_recursive/main.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import immutable/list
import immutable/option
import io/args
import text/string

def fibonacci(n: Int): Int =
if (n == 0) {
0
} else if (n == 1) {
1
} else {
fibonacci(n - 1) + fibonacci(n - 2)
}

def main() = {
val n = commandLineArgs().headOption.getOrElse { "" }.toInt.getOrElse { 5 };
val r = fibonacci(n);
println(r)
}
31 changes: 31 additions & 0 deletions benchmarks/effekt/iterator/main.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import immutable/list
import immutable/option
import io/args
import text/string

effect Emit(e: Int): Unit

def range(l: Int, u: Int): Unit / Emit =
if (l > u) {
()
} else {
do Emit(l);
range(l + 1, u)
}

def run(n: Int) = {
var s = 0;
try {
range(0, n);
s
} with Emit { (e: Int) =>
s = s + e;
resume(())
}
}

def main() = {
val n = commandLineArgs().headOption.getOrElse { "" }.toInt.getOrElse { 5 };
val r = run(n);
println(r)
}
58 changes: 58 additions & 0 deletions benchmarks/effekt/nqueens/main.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import immutable/list
import immutable/option
import io/args
import text/string

type Solution = List[Int]

effect Search {
def pick(size: Int): Int
def fail(): Nothing
}

def safe(queen: Int, diag: Int, xs: Solution): Boolean =
xs match {
case Nil() => true
case Cons(q, qs) => if (queen != q && queen != q + diag && queen != q - diag) {
safe(queen, diag + 1, qs)
} else {
false
}
}

def place(size: Int, column: Int) : Solution / Search =
if (column == 0) {
Nil()
} else {
val rest = place(size, column - 1);
val next = do pick(size);
if (safe(next, 1, rest)) {
Cons(next, rest)
} else {
do fail() match {}
}
}

def run(n: Int): Int =
try {
place(n, n);
1
} with Search {
def fail() = 0
def pick(size) = {
def loop(i: Int, a: Int): Int = {
if (i == size) {
a + resume(i)
} else {
loop(i + 1, a + resume(i))
}
};
loop(1, 0)
}
}

def main() = {
val n = commandLineArgs().headOption.getOrElse { "" }.toInt.getOrElse { 5 };
val r = run(n);
println(r)
}
79 changes: 79 additions & 0 deletions benchmarks/effekt/parsing_dollars/main.effekt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import immutable/list
import immutable/option
import io/args
import text/string

type Chr = Int

effect Read(): Chr

effect Emit(e: Int): Unit

effect Stop(): Nothing

def newline() =
10
def isNewline(c: Chr) =
c == 10
def dollar(): Chr =
36
def isDollar(c: Chr) =
c == 36

def parse(a: Int): Unit / {Read, Emit, Stop} = {
val c = do Read();
if (isDollar(c)) {
parse(a + 1)
} else if (isNewline(c)) {
do Emit(a);
parse(0)
} else {
do Stop()
}
}

def sum { action: () => Unit / Emit } = {
var s = 0;
try {
action()
} with Emit { (e: Int) =>
s = s + e;
resume(())
};
s
}

def catch { action: () => Unit / Stop } =
try {
action()
} with Stop { () =>
()
}

def feed(n: Int) { action: () => Unit / Read } = {
var i = 0;
var j = 0;
try {
action()
} with Read { () =>
if (i > n) {
do Stop() match {}
} else if (j == 0) {
i = i + 1;
j = i;
resume(newline())
} else {
j = j - 1;
resume(dollar())
}
}
}

def run(n: Int) =
sum { catch { feed(n) { parse(0) } } }

def main() = {
val n = commandLineArgs().headOption.getOrElse { "" }.toInt.getOrElse { 10 };
val r = run(n);
println(r)
}
Loading

0 comments on commit 6845589

Please sign in to comment.