diff --git a/examples/benchmarks/.github/workflows/tests.yml b/examples/benchmarks/.github/workflows/tests.yml
new file mode 100644
index 00000000..89136858
--- /dev/null
+++ b/examples/benchmarks/.github/workflows/tests.yml
@@ -0,0 +1,20 @@
+name: Tests
+
+on:
+ push:
+ branches: ["main"]
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: aiken-lang/setup-aiken@v0.1.0
+ with:
+ version: v1
+
+ - run: aiken fmt --check
+ - run: aiken check -D
+ - run: aiken build
diff --git a/examples/benchmarks/.gitignore b/examples/benchmarks/.gitignore
new file mode 100644
index 00000000..ff7811b1
--- /dev/null
+++ b/examples/benchmarks/.gitignore
@@ -0,0 +1,6 @@
+# Aiken compilation artifacts
+artifacts/
+# Aiken's project working directory
+build/
+# Aiken's default documentation export
+docs/
diff --git a/examples/benchmarks/README.md b/examples/benchmarks/README.md
new file mode 100644
index 00000000..3564414e
--- /dev/null
+++ b/examples/benchmarks/README.md
@@ -0,0 +1,55 @@
+# benchmarks
+
+Write validators in the `validators` folder, and supporting functions in the `lib` folder using `.ak` as a file extension.
+
+For example, as `validators/always_true.ak`
+
+```gleam
+validator {
+ fn spend(_datum: Data, _redeemer: Data, _context: Data) -> Bool {
+ True
+ }
+}
+```
+
+## Building
+
+```sh
+aiken build
+```
+
+## Testing
+
+You can write tests in any module using the `test` keyword. For example:
+
+```gleam
+test foo() {
+ 1 + 1 == 2
+}
+```
+
+To run all tests, simply do:
+
+```sh
+aiken check
+```
+
+To run only tests matching the string `foo`, do:
+
+```sh
+aiken check -m foo
+```
+
+## Documentation
+
+If you're writing a library, you might want to generate an HTML documentation for it.
+
+Use:
+
+```sh
+aiken docs
+```
+
+## Resources
+
+Find more on the [Aiken's user manual](https://aiken-lang.org).
diff --git a/examples/benchmarks/aiken.lock b/examples/benchmarks/aiken.lock
new file mode 100644
index 00000000..0a72eb3c
--- /dev/null
+++ b/examples/benchmarks/aiken.lock
@@ -0,0 +1,15 @@
+# This file was generated by Aiken
+# You typically do not need to edit this file
+
+[[requirements]]
+name = "aiken-lang/stdlib"
+version = "1.7.0"
+source = "github"
+
+[[packages]]
+name = "aiken-lang/stdlib"
+version = "1.7.0"
+requirements = []
+source = "github"
+
+[etags]
diff --git a/examples/benchmarks/aiken.toml b/examples/benchmarks/aiken.toml
new file mode 100644
index 00000000..7223d60f
--- /dev/null
+++ b/examples/benchmarks/aiken.toml
@@ -0,0 +1,14 @@
+name = "aiken/benchmarks"
+version = "0.0.0"
+license = "Apache-2.0"
+description = "Aiken contracts for project 'aiken/benchmarks'"
+
+[repository]
+user = "aiken"
+project = "benchmarks"
+platform = "github"
+
+[[dependencies]]
+name = "aiken-lang/stdlib"
+version = "1.7.0"
+source = "github"
diff --git a/examples/benchmarks/lib/benchmarks/knights.ak b/examples/benchmarks/lib/benchmarks/knights.ak
new file mode 100644
index 00000000..d99b2ec8
--- /dev/null
+++ b/examples/benchmarks/lib/benchmarks/knights.ak
@@ -0,0 +1,71 @@
+use aiken/list
+use benchmarks/knights/heuristic.{descendants, finished_tour, start_tour}
+use benchmarks/knights/types.{ChessSet, Solution}
+use benchmarks/queue.{
+ Queue, append_all_front, append_front, create_queue, head, is_empty,
+ remove_front, to_list,
+}
+
+test run_knights0() {
+ run_knights(0, 0) == []
+}
+
+test run_knights1() {
+ run_knights(2, 2) == []
+}
+
+fn run_knights(depth: Int, board_size: Int) -> Solution {
+ depth_search(depth, root(board_size), grow, is_fin) |> to_list
+}
+
+fn depth_search(
+ depth: Int,
+ queue: Queue,
+ grow_fn: fn(a) -> List,
+ fin_fn: fn(a) -> Bool,
+) -> Queue {
+ if depth == 0 || is_empty(queue) {
+ create_queue()
+ } else if fin_fn(head(queue)) {
+ depth_search(depth - 1, remove_front(queue), grow_fn, fin_fn)
+ |> append_front(head(queue))
+ } else {
+ append_all_front(remove_front(queue), grow_fn(head(queue)))
+ |> depth_search(depth - 1, _, grow_fn, fin_fn)
+ }
+}
+
+fn root(sze: Int) -> Queue<(Int, ChessSet)> {
+ append_all_front(create_queue(), mk_starts(sze))
+}
+
+fn mk_starts(sze: Int) -> List<(Int, ChessSet)> {
+ let x_list = interval(1, sze)
+ let y_list = interval(1, sze)
+
+ let l = x_list |> list.map2(y_list, fn(a, b) { start_tour((a, b), sze) })
+ let length = list.length(l)
+
+ list.repeat(1 - length, length) |> list.zip(l)
+}
+
+fn interval(a: Int, b: Int) -> List {
+ if a > b {
+ []
+ } else {
+ [a, ..interval(a + 1, b)]
+ }
+}
+
+fn grow(item: (Int, ChessSet)) -> List<(Int, ChessSet)> {
+ let (x, y) = item
+
+ let const_item = x + 1
+ descendants(y) |> list.map(fn(list_item) { (const_item, list_item) })
+}
+
+fn is_fin(item: (Int, ChessSet)) -> Bool {
+ let (_, y) = item
+
+ finished_tour(y)
+}
diff --git a/examples/benchmarks/lib/benchmarks/knights/chess_set.ak b/examples/benchmarks/lib/benchmarks/knights/chess_set.ak
new file mode 100644
index 00000000..4ff445e4
--- /dev/null
+++ b/examples/benchmarks/lib/benchmarks/knights/chess_set.ak
@@ -0,0 +1,172 @@
+use aiken/builtin
+use aiken/list
+use benchmarks/knights/types.{ChessSet, Tile}
+
+pub fn create_board(size: Int, init_square: Tile) -> ChessSet {
+ ChessSet {
+ size,
+ move_number: 1,
+ start: Some(init_square),
+ visited: [init_square],
+ }
+}
+
+pub fn add_piece(board: ChessSet, tile: Tile) -> ChessSet {
+ // record update
+ ChessSet {
+ ..board,
+ move_number: board.move_number + 1,
+ visited: [tile, ..board.visited],
+ }
+}
+
+pub fn first_piece(board: ChessSet) -> Tile {
+ expect Some(tile) = board.start
+ tile
+}
+
+pub fn delete_first(board: ChessSet) -> ChessSet {
+ let visited = board.visited
+
+ expect Some(deleted_first) = list.init(visited)
+
+ ChessSet { ..board, start: second_last(visited), visited: deleted_first }
+}
+
+pub fn second_last(visited: List) -> Option {
+ when visited is {
+ [] -> None
+ [_, ..rest] -> {
+ let value = second_last(rest)
+
+ if value == None {
+ if builtin.null_list(rest) {
+ None
+ } else {
+ Some(builtin.head_list(visited))
+ }
+ } else {
+ value
+ }
+ }
+ }
+}
+// {-# INLINABLE createBoard #-}
+// createBoard :: Integer -> Tile -> ChessSet
+// createBoard x t = Board x 1 (Just t) [t]
+
+// {-# INLINABLE sizeBoard #-}
+// sizeBoard :: ChessSet -> Integer
+// sizeBoard (Board s _ _ _) = s
+
+// {-# INLINABLE noPieces #-}
+// noPieces :: ChessSet -> Integer
+// noPieces (Board _ n _ _) = n
+
+// {-# INLINABLE addPiece #-}
+// addPiece :: Tile -> ChessSet -> ChessSet
+// addPiece t (Board s n f ts) = Board s (n+1) f (t:ts)
+
+// -- % Remove the last element from a list
+// {-# INLINABLE init #-}
+// init :: [a] -> [a]
+// init l = case reverse l of
+// _:as -> reverse as
+// [] -> Tx.error ()
+
+// {-# INLINABLE secondLast #-}
+// secondLast :: [a] -> Maybe a
+// secondLast l =
+// case reverse l of
+// [] -> Tx.error ()
+// [_] -> Nothing
+// _:a:_ -> Just a
+
+// {-% Note [deleteFirst].
+// deleteFirst removes the first position from the tour.
+// Since the sequence of positions (ts) is stored in reverse this involves
+// deleting the last element of ts and also storing the second-last element of
+// ts as the new starting position. In the strict world this will *fail* if the
+// length of ts is 1. The lazy version got away with this because the starting
+// position is never examined in that case (possibly just through luck: with
+// enough backtracking that might still happen). To solve this we have to store
+// the starting position as a Maybe value, deferring any error until we actually
+// look at it.
+// %-}
+
+// {-# INLINABLE deleteFirst #-}
+// deleteFirst :: ChessSet -> ChessSet
+// deleteFirst (Board s n _ ts) =
+// Board s (n-1) f' ts'
+// where ts' = init ts
+// f' = secondLast ts
+
+// {-# INLINABLE positionPiece #-}
+// positionPiece :: Integer -> ChessSet -> Tile
+// positionPiece x (Board _ n _ ts) = ts Tx.!! (n - x)
+
+// {-# INLINABLE lastPiece #-}
+// lastPiece :: ChessSet -> Tile
+// lastPiece (Board _ _ _ (t:_)) = t
+// lastPiece _ = Tx.error ()
+
+// {-# INLINABLE firstPiece #-}
+// firstPiece :: ChessSet -> Tile
+// firstPiece (Board _ _ f _) =
+// case f of Just tile -> tile
+// Nothing -> Tx.error ()
+
+// {-# INLINABLE pieceAtTile #-}
+// pieceAtTile :: Tile -> ChessSet -> Integer
+// pieceAtTile x0 (Board _ _ _ ts)
+// = findPiece x0 ts
+// where
+// findPiece _ [] = Tx.error ()
+// findPiece x (y:xs)
+// | x == y = 1 + Tx.length xs
+// | otherwise = findPiece x xs
+
+// {-# INLINABLE notIn #-}
+// notIn :: Eq a => a -> [a] -> Bool
+// notIn _ [] = True
+// notIn x (a:as) = (x /= a) && (notIn x as)
+
+// {-# INLINABLE isSquareFree #-}
+// isSquareFree :: Tile -> ChessSet -> Bool
+// isSquareFree x (Board _ _ _ ts) = notIn x ts
+
+// -- % Everything below here is only needed for printing boards.
+// -- % This is useful for debugging.
+
+// instance Haskell.Show ChessSet where
+// showsPrec _ (Board sze n _ ts)
+// = Haskell.showString (printBoard sze sortedTrail 1)
+// where sortedTrail = quickSort (assignMoveNo ts sze n)
+
+// assignMoveNo :: [Tile] -> Integer -> Integer -> [Tile]
+// assignMoveNo [] _ _
+// = []
+// assignMoveNo ((x,y):t) size z
+// = (((y-1)*size)+x,z):assignMoveNo t size (z-1)
+
+// printBoard :: Integer -> [Tile] -> Integer -> Haskell.String
+// printBoard s [] n
+// | (n > (s*s)) = ""
+// | ((n `Haskell.mod` s) /=0)= "*"++(spaces (s*s) 1) ++(printBoard s [] (n+1))
+// | ((n `Haskell.mod` s) ==0)= "*\n" ++(printBoard s [] (n+1))
+// printBoard s trail@((i,j):xs) n
+// | (i==n) &&
+// ((n `Haskell.mod` s) ==0) = (Haskell.show j)++"\n"++(printBoard s xs (n+1))
+// | (i==n) &&
+// ((n `Haskell.mod` s) /=0)= (Haskell.show j)++(spaces (s*s) j)++(printBoard s xs (n+1))
+// | ((n `Haskell.mod` s) /=0)= "*" ++(spaces (s*s) 1)++(printBoard s trail (n+1))
+// | ((n `Haskell.mod` s) ==0)= "*\n" ++(printBoard s trail (n+1))
+// printBoard _ _ _ = "?"
+
+// spaces :: Integer -> Integer -> Haskell.String
+// spaces s y =
+// take' ((logTen s) - (logTen y) + 1) [' ',' '..]
+// where
+// logTen :: Integer -> Integer
+// logTen 0 = 0
+// logTen x = 1 + logTen (x `Haskell.div` 10)
diff --git a/examples/benchmarks/lib/benchmarks/knights/heuristic.ak b/examples/benchmarks/lib/benchmarks/knights/heuristic.ak
new file mode 100644
index 00000000..f736cd32
--- /dev/null
+++ b/examples/benchmarks/lib/benchmarks/knights/heuristic.ak
@@ -0,0 +1,142 @@
+use aiken/builtin
+use aiken/list
+use benchmarks/knights/chess_set.{add_piece, create_board, first_piece}
+use benchmarks/knights/sort.{quick_sort}
+use benchmarks/knights/types.{ChessSet, Tile}
+
+pub fn start_tour(st: Tile, size: Int) -> ChessSet {
+ expect 0 = builtin.remainder_integer(size, 2)
+
+ create_board(size, st)
+}
+
+pub fn finished_tour(board: ChessSet) -> Bool {
+ let ChessSet { move_number, size, .. } = board
+
+ move_number == size * size && can_jump_first(board)
+}
+
+pub fn descendants(board: ChessSet) -> List {
+ if and {
+ can_jump_first(board),
+ board
+ |> add_piece(first_piece(board))
+ |> dead_end,
+ } {
+ []
+ } else {
+ let singles = single_descend(board)
+
+ when singles is {
+ [] -> board |> desc_and_no |> quick_sort |> list.map(builtin.snd_pair)
+ [_] -> singles
+ _ ->
+ []
+ }
+ }
+}
+
+pub fn can_jump_first(board: ChessSet) -> Bool {
+ todo
+}
+
+pub fn dead_end(board: ChessSet) -> Bool {
+ todo
+}
+
+pub fn single_descend(board: ChessSet) -> List {
+ todo
+}
+
+pub fn desc_and_no(board: ChessSet) -> List<(Int, ChessSet)> {
+ todo
+}
+
+pub fn can_move_to(board: ChessSet, tile: Tile) -> Bool {
+ todo
+}
+// data Direction = UL | UR | DL |DR | LU | LD | RU | RD
+
+// {-# INLINABLE move #-}
+// move :: Direction -> Tile -> Tile
+// move UL (x,y) = (x-1,y-2)
+// move UR (x,y) = (x+1,y-2)
+// move DL (x,y) = (x-1,y+2)
+// move DR (x,y) = (x+1,y+2)
+// move LU (x,y) = (x-2,y-1)
+// move LD (x,y) = (x-2,y+1)
+// move RU (x,y) = (x+2,y-1)
+// move RD (x,y) = (x+2,y+1)
+
+// {-# INLINABLE startTour #-}
+// startTour :: Tile -> Integer -> ChessSet
+// startTour st size
+// | (size `Tx.remainder` 2) == 0 = createBoard size st
+// | otherwise = {-Tx.trace "startTour" $ -} Tx.error ()
+
+// {-# INLINABLE moveKnight #-}
+// moveKnight :: ChessSet -> Direction -> ChessSet
+// moveKnight board dir
+// = addPiece (move dir (lastPiece board)) board
+
+// {-# INLINABLE canMove #-}
+// canMove :: ChessSet -> Direction -> Bool
+// canMove board dir
+// = canMoveTo (move dir (lastPiece board)) board
+
+// {-# INLINABLE canMoveTo #-}
+// canMoveTo :: Tile -> ChessSet -> Bool
+// canMoveTo t@(x,y) board
+// = (x Tx.>= 1) && (x Tx.<= sze) &&
+// (y Tx.>= 1) && (y Tx.<= sze) &&
+// isSquareFree t board
+// where
+// sze = sizeBoard board
+
+// {-# INLINABLE descendents #-}
+// descendents :: ChessSet -> [ChessSet]
+// descendents board =
+// if (canJumpFirst board) && (deadEnd (addPiece (firstPiece board) board))
+// then []
+// else
+// let l = Tx.length singles in
+// if l == 0 then map snd (quickSort (descAndNo board))
+// else if l == 1 then singles
+// else [] -- Going to be dead end
+// where
+// singles = singleDescend board
+
+// {-# INLINABLE singleDescend #-}
+// singleDescend :: ChessSet -> [ChessSet]
+// singleDescend board =[x | (y,x) <- descAndNo board, y==1]
+
+// {-# INLINABLE descAndNo #-}
+// descAndNo :: ChessSet -> [(Integer,ChessSet)]
+// descAndNo board
+// = [(Tx.length (possibleMoves (deleteFirst x)),x) | x <- allDescend board]
+
+// {-# INLINABLE allDescend #-}
+// allDescend :: ChessSet -> [ChessSet]
+// allDescend board
+// = map (moveKnight board) (possibleMoves board)
+
+// {-# INLINABLE possibleMoves #-}
+// possibleMoves :: ChessSet -> [Direction]
+// possibleMoves board
+// =[x | x <- [UL,UR,DL,DR,LU,LD,RU,RD], (canMove board x)]
+
+// {-# INLINABLE deadEnd #-}
+// deadEnd :: ChessSet -> Bool
+// deadEnd board = (Tx.length (possibleMoves board)) == 0
+
+// {-# INLINABLE canJumpFirst #-}
+// canJumpFirst :: ChessSet -> Bool
+// canJumpFirst board
+// = canMoveTo (firstPiece board) (deleteFirst board)
+
+// {-# INLINABLE tourFinished #-}
+// tourFinished :: ChessSet -> Bool
+// tourFinished board
+// = (noPieces board == (sze*sze)) && (canJumpFirst board)
+// where
+// sze = sizeBoard board
diff --git a/examples/benchmarks/lib/benchmarks/knights/sort.ak b/examples/benchmarks/lib/benchmarks/knights/sort.ak
new file mode 100644
index 00000000..6e429da9
--- /dev/null
+++ b/examples/benchmarks/lib/benchmarks/knights/sort.ak
@@ -0,0 +1,3 @@
+pub fn quick_sort(l: List) -> List {
+ todo
+}
diff --git a/examples/benchmarks/lib/benchmarks/knights/types.ak b/examples/benchmarks/lib/benchmarks/knights/types.ak
new file mode 100644
index 00000000..75449ffb
--- /dev/null
+++ b/examples/benchmarks/lib/benchmarks/knights/types.ak
@@ -0,0 +1,12 @@
+pub type Tile =
+ (Int, Int)
+
+pub type ChessSet {
+ move_number: Int,
+ visited: List,
+ size: Int,
+ start: Option,
+}
+
+pub type Solution =
+ List<(Int, ChessSet)>
diff --git a/examples/benchmarks/lib/benchmarks/queue.ak b/examples/benchmarks/lib/benchmarks/queue.ak
new file mode 100644
index 00000000..9a5fbb06
--- /dev/null
+++ b/examples/benchmarks/lib/benchmarks/queue.ak
@@ -0,0 +1,41 @@
+use aiken/list
+
+pub opaque type Queue {
+ inner: List,
+}
+
+pub fn create_queue() -> Queue {
+ [] |> Queue
+}
+
+pub fn to_list(queue: Queue) -> List {
+ queue.inner
+}
+
+pub fn is_empty(queue: Queue) -> Bool {
+ when queue.inner is {
+ [] -> True
+ _ -> False
+ }
+}
+
+pub fn append_front(queue: Queue, item: a) -> Queue {
+ list.push(queue.inner, item) |> Queue
+}
+
+/// Add all items from the list to the front of the queue
+pub fn append_all_front(queue: Queue, items: List) -> Queue {
+ list.concat(items, queue.inner) |> Queue
+}
+
+pub fn remove_front(queue: Queue) -> Queue {
+ expect [_, ..rest] = queue.inner
+
+ rest |> Queue
+}
+
+pub fn head(queue: Queue) -> a {
+ expect [q, ..] = queue.inner
+
+ q
+}
diff --git a/examples/benchmarks/plutus.json b/examples/benchmarks/plutus.json
new file mode 100644
index 00000000..5c4319e1
--- /dev/null
+++ b/examples/benchmarks/plutus.json
@@ -0,0 +1,14 @@
+{
+ "preamble": {
+ "title": "aiken/benchmarks",
+ "description": "Aiken contracts for project 'aiken/benchmarks'",
+ "version": "0.0.0",
+ "plutusVersion": "v2",
+ "compiler": {
+ "name": "Aiken",
+ "version": "v1.0.21-alpha+4b04517"
+ },
+ "license": "Apache-2.0"
+ },
+ "validators": []
+}
\ No newline at end of file
diff --git a/examples/hello_world/aiken.toml b/examples/hello_world/aiken.toml
index 3b523f22..1e530f11 100644
--- a/examples/hello_world/aiken.toml
+++ b/examples/hello_world/aiken.toml
@@ -5,5 +5,5 @@ description = "Aiken contracts for project 'aiken-lang/hello_world'"
[[dependencies]]
name = "aiken-lang/stdlib"
-version = "main"
+version = "1.7.0"
source = "github"
diff --git a/examples/hello_world/plutus.json b/examples/hello_world/plutus.json
index a0fab843..5b6e3cc0 100644
--- a/examples/hello_world/plutus.json
+++ b/examples/hello_world/plutus.json
@@ -6,7 +6,7 @@
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
- "version": "v1.0.19-alpha+d56d518"
+ "version": "v1.0.21-alpha+4b04517"
}
},
"validators": [