• Stars
    star
    129
  • Rank 279,262 (Top 6 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created over 5 years ago
  • Updated about 2 months ago

Reviews

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

Repository Details

an implementation of stuck macros

Klister

Klister [TyDe 2020, video] is a programming language, a research prototype which combines features from Racket, ML, and a strict Haskell into a single language. It is named after its most distinguishing feature, "stuck macros" [Compose NYC 2019], as "Klister" is Danish for "adhesive".

#lang "prelude.kl"

-- do notation is not builtin syntax, it's implemented as a library!
(import "monad.kl")

-- An effectful action whose inferred type is (-> String (IO Unit))
(defun putStrLn (str)
  (write stdout (string-append str "\n")))

-- "run" is like main, except you can have more than one.
(run
  -- Klister doesn't have type classes yet, so "do" needs an explicit
  -- dictionary argument.
  (do io-monad
    (putStrLn "hello")
    (putStrLn "world")))

You can run the above program using either stack or cabal:

$ cabal run klister -- run examples/hello.kl
hello
world

Features

Features we borrow from Racket:

  • Custom syntax, via hygienic macros with easy-to-override hygiene.
  • Custom languages (#lang), via macros which reinterpret terms into those of an existing #lang.
  • Syntax objects, that is, s-expressions annotated with source locations and lexical information.
  • A module system which respects the phase system. Thus, if Klister one day supports generating binaries, those binaries will not be unnecessarily clogged with dependencies which were only needed at compile-time.

Features we borrow from ML:

  • A type system with parametric polymorphism, algebraic datatypes, and Hindley-Milner type inference.

Features we borrow from Haskell:

  • Monadic macros; our macros have type (-> Syntax (Macro Syntax)), where Macro Syntax is similar to Q Exp in TemplateHaskell. Note that this type implies that a macro is allowed to generate ill-typed code; this error is caught where the macro is called, not where the macro is defined. We thus aim for the expressivity of Template Haskell, not the extra guarantees of Typed Template Haskell.
  • Purely functional; primitives with compile-time side-effects (e.g. comparing identifiers while taking into account the current set of bindings) run in the Macro monad, while primitives with runtime side-effects (e.g. printing to stdout) run in the IO monad.
  • Higher-kinded types; for example monads are defined as a library.

Features which make Klister special (but not necessarily unique; see the bibliography for languages with similar features):

  • Type-providing macros; a macro can provide type information about the code it plans to generate.
  • Type-aware macros; a macro can obtain type requirements about the code it needs to generate.
  • Stuck macros; the above two features make it possible for macros to communicate, and thus to affect what each other generates. The language primitives are designed so that the order in which the macros are expanded cannot affect their results, and indeed the same is true for the order in which the macro expansion and type-inference steps are interleaved. This means that the order in which the type checker traverses a program and generates constraints is not visible to the authors of macros, providing a predictable programming model. This makes Klister code more robust to refactorings which affect that order.
  • Problem-aware macros; in addition to the type, a macro can learn which "problem" it needs to solve, namely whether it must generate an expression, a type, a pattern, etc. Each problem would correspond to a form of judgment if the language was formalized, e.g. a typing judgment for the expression problem, a well-formed type judgment for the type problem, etc.

Cool things which can be built using the above features:

  • Macros communicating via types
  • Custom type-driven code generation, via macros which generate code from a type.
  • Languages with custom type systems, via macros which reinterpret types into those of an existing #lang, and which contribute to type inference by providing type information about the code they generate. The variety of type-systems which can be implemented this way is unforunately limited by the core type system to which everything must be rewritten.
  • Languages with custom implicit terms, via macros which generate terms of an existing #lang based on a type in the new #lang.

While we think Klister demonstrates some neat ideas, there are some limitations which make Klister an impractical choice for most real-life projects. If you want to help make Klister a more practical language, please reach out!

Here are the most prominent Racket features which are missing from Klister:

  • Klister does not yet support custom readers, and thus every #lang looks like a Lisp. This also limits languages to Integer literals and String literals.
  • local-expand is planned, but not yet implemented.
  • Syntax parameters are planned, but not yet implemented.

Here are the most prominent Haskell features which are missing from Klister:

  • Type classes are planned as a library, but are not yet implemented.
  • Type annotations containing foralls are planned, but not yet implemented. Currently, Klister only supports type ascriptions, e.g. (+ (the Integer (* 2 3)) 1), for giving the type of a sub-expression.
  • Klister does not support GADTs nor type families.

Here are the most prominent features which Racket and Haskell both have but which are missing from Klister:

  • Klister is missing commonly-expected datatypes like Map, Set, and Double.
  • Klister requires functions and datatypes to be defined before they are used.
  • Klister does not support concurrency. It might be possible to implement a #lang with a green thread scheduler.
  • Klister does not support exception-handling. error and syntax-error both terminate the program immediately, like panic! in Rust. It is definitely possible to implement Either-based error handling, and it should be possible to implement a #lang in which exceptions are an ambient effect.
  • Klister does not have a rich ecosystem of libraries. It does not have a package repository where individual contributors can release their own packages. Please upload your Klister code to the examples folder, it currently contains all the Klister code which was ever written.
  • Klister does not have a rich set of IO primitives out of which you could build all the libraries you need yourself. Currently, you can only print to stdout.
  • A Foreign-Function-Interface (FFI), to reuse Haskell's rich ecosystem of libraries (and its own FFI to C), is planned but not yet implemented.
  • Expanding modules separately, to speed up expansion times, is planned but not yet implemented.
  • Klister does not produce binary executables.

Guide and Reference

The Klister Guide consists of the various commented examples linked from the above feature list, plus the extra information in the sub-sections below.

The Klister Reference covers every identifier in the "prelude.kl" language, but doesn't currently say much about each. It consists of a list of examples showing how to use the macros, and a list of type signatures documenting how to use the values and functions.

Imports

The import form will search for modules in the same directory as the importing module, and in directories listed in the KLISTERPATH environment variable, a :-separated list of directories.

More Repositories

1

frp-zoo

Comparing many FRP implementations by reimplementing the same toy app in each.
Haskell
490
star
2

hawk

Haskell text processor for the command-line
Haskell
361
star
3

git-slides

Text-based slides using vim and git.
Shell
152
star
4

category-syntax

do-notation for Category and "Arrow without arr"
Haskell
63
star
5

typelevel-rewrite-rules

rewrite rules for type-level equalities
Haskell
62
star
6

linear-examples

Example uses of linear types
Haskell
42
star
7

n-ary-functor

A single typeclass for Functor, Bifunctor, Trifunctor, etc.
Haskell
40
star
8

conway

Demonstrating comonad transformers.
Haskell
35
star
9

hyzzy

A framework for defining text adventures via Haskell files. Play by combining functions, not by guessing phrases.
Haskell
32
star
10

ludum-dare-31

The theme for LD31 was "Entire Game on One Screen"
Haskell
29
star
11

magic-typelevel-elem

Demonstrating how to make type families faster using typechecker plugins
Haskell
21
star
12

cabal-rangefinder

A tool to fill in the version ranges in a cabal file.
Haskell
17
star
13

mastering-haskell

The slides for my Packt course, "Mastering Haskell".
Shell
15
star
14

commutative

Using Haskell's type system to guarantee commutativity.
Haskell
15
star
15

typechecker-combinators

Haskell
15
star
16

laughable

Clowns to the left of me, jokers to the right
Haskell
13
star
17

deploy-hint

Demonstrating that you don't need to install ghc in order to use the hint library.
Haskell
11
star
18

surjective

An output coverage checker
Haskell
11
star
19

giggles-is-you

A reimplementation of Baba is You in Haskell, for our weekly haskell-beginners presentations.
Haskell
9
star
20

strongly-typed-bound

My version of Kmett's "strongly typed bound for acowley" snippet.
Haskell
9
star
21

circular-sig

a twelf-like type-checker supporting recursive signatures
Haskell
8
star
22

objc2java

Convert pure ObjectiveC code to pure Java code, libraries be damned.
Haskell
8
star
23

ludum-dare-35

The theme for LD35 was: "shapeshift"
Elm
8
star
24

nominalize

Generate types using type-generic programming, retaining control over the names of the constructors and the fields.
Haskell
6
star
25

image-watcher

Display an image and update it when the file changes
Haskell
6
star
26

ludum-dare-34

The themes for LD34 were: "two button controls" and "growing"
JavaScript
6
star
27

apecs-hint-demo

demonstrating how to use hint to dynamically modify the game world of an apecs-based game
Haskell
5
star
28

slides

A place to host my git-slides presentations
5
star
29

stm-variants

The STM API we know and love, but useable in more circumstances
Haskell
5
star
30

acme-tiny-rules

a parody of Tiny Glade with inference rules instead of castles
Haskell
5
star
31

dot-utils

A set of small command-line tools for transforming GraphViz dot-files
Haskell
4
star
32

k-playground

for implementing toy languages using the K Framework
Haskell
4
star
33

acme-circular-containers

Spineless containers which are fast to read but inefficient to update
Haskell
4
star
34

jira-dependencies

from JIRA's .csv export to graphviz's dot format
Haskell
4
star
35

tarjan

an agda implementation of Tarjan's strongly connected components algorithm
Agda
3
star
36

chopt-test-task

Haskell
3
star
37

worldly

based on Conor McBride's "Worldly Type Systems" talk
Haskell
3
star
38

ludum-dare-44

The theme for LD44 was "Your life is currency"
Rust
3
star
39

agda-playground

a series of ambitious experiments in the functional language / proof assistant Agda.
Vim Script
3
star
40

transliterator

Haskell
3
star
41

premonoidal

Agda encoding of premonoidal categories
Agda
3
star
42

submake

Use git to replay part of a bash pipeline.
Haskell
2
star
43

directed-graph-ui

A tool for creating directed graphs.
JavaScript
2
star
44

ice-cream-privacy

Haskell
2
star
45

rerec

Haskell
2
star
46

hs-promote

C++-style type promotion for Haskell's numeric hierarchy
Haskell
2
star
47

hint-demo

Haskell
2
star
48

trie-based-frp

An implementation of higher-order FRP based on shared tries instead of unsafePerformIO.
Haskell
2
star
49

glut-events

For writing GLUT's main loop in the style of Haskell's main function.
Haskell
2
star
50

reactive-banana-anti-tutorial

companion code for my blog post
Haskell
2
star
51

queues

Compare the performance of a few Haskell queue implementations.
Haskell
2
star
52

relocation-bug

Haskell
1
star
53

raml

C
1
star
54

contravariant-case

An API for Divisible and Decidable which looks like pattern-matching.
Haskell
1
star
55

ludum-dare-42

The theme for LD42 was "Running out of Space"
TypeScript
1
star
56

adicity

A DSL in which composition and application are unified.
Haskell
1
star
57

stack-bug

A demonstration of a bug which doesn't fit in a gist because it requires directories.
Haskell
1
star
58

free-premonoidal

Haskell
1
star
59

existentials

A type-level DSL for placing existential constraints on some arguments of a type constructor
Haskell
1
star
60

haskell-code-explorer-bug

a minimal repro
Haskell
1
star
61

croportunity-cost

A game about clicking and not clicking on plants.
Elm
1
star
62

ludum-dare-43

Haskell
1
star
63

timesheet

Simple text-based time tracking
Haskell
1
star
64

pure-framework-chat

Haskell
1
star
65

tic-tac-top

The AI for a tiny board game I invented.
Haskell
1
star
66

face-down

Haskell
1
star
67

install-before-test

How to configure project.cabal so that tests are run after the install.
Haskell
1
star
68

memento

Write a Virtual DOM for anything!
Haskell
1
star
69

dotfiles

My default setup, including config files and shell scripts.
Python
1
star
70

gif-browser

a tiny application for browsing through the frames of an animated gif.
Haskell
1
star
71

lens-syntax

Pointful syntax for optic compositions
Haskell
1
star