initial commit
Getty Ritter
9 years ago
| 1 |
# PicoML
|
| 2 |
|
| 3 |
A minimal statically-typed functional programming language. Not actually
|
| 4 |
an ML. Written entirely in cross-platform C; allows for multiple code
|
| 5 |
generators.
|
| 6 |
|
| 7 |
Exhaustive feature list:
|
| 8 |
|
| 9 |
- sums (eager)
|
| 10 |
- products (lazy)
|
| 11 |
- functions
|
| 12 |
- currying
|
| 13 |
- closures
|
| 14 |
- references
|
| 15 |
- implicit values (searched by type, must be unambiguous)
|
| 16 |
- libc bindings (incl. malloc)
|
| 17 |
|
| 18 |
Maybe looking like
|
| 19 |
|
| 20 |
~~~~
|
| 21 |
data List a =
|
| 22 |
[ Cons a (List a)
|
| 23 |
, Nil
|
| 24 |
]
|
| 25 |
|
| 26 |
map (f : a -> b) (l : List a) : List b =
|
| 27 |
case l of
|
| 28 |
Cons x xs -> Cons (f x) (map f xs)
|
| 29 |
Nil -> Nil
|
| 30 |
|
| 31 |
record Stream a =
|
| 32 |
{ .head a
|
| 33 |
, .tail (Stream a)
|
| 34 |
}
|
| 35 |
|
| 36 |
mapS (f : a -> b) (s : Stream a) : Stream b =
|
| 37 |
{ .head = f s.head
|
| 38 |
, .tail = mapS f s.tail
|
| 39 |
}
|
| 40 |
|
| 41 |
record Functor f = { .fmap ((a -> b) -> f a -> f b) }
|
| 42 |
|
| 43 |
implicit listFunctor : Functor List = { .fmap = map }
|
| 44 |
implicit streamFunctor : Functor Stream = { .fmap = mapS }
|
| 45 |
~~~~
|
| 1 |
#include "ast.h"
|
| 2 |
#include <stdlib.h>
|
| 3 |
#include <string.h>
|
| 4 |
|
| 5 |
char*
|
| 6 |
str_of_slice(slice_t slice)
|
| 7 |
{
|
| 8 |
char* str = malloc(slice.len + 1);
|
| 9 |
if (!str) return 0;
|
| 10 |
strncpy(str, slice.start, slice.len);
|
| 11 |
str[slice.len] = '\0';
|
| 12 |
return str;
|
| 13 |
}
|
| 1 |
struct slice {
|
| 2 |
char *start;
|
| 3 |
size_t len;
|
| 4 |
size_t indentation;
|
| 5 |
} slice_t;
|
| 6 |
|
| 7 |
typedef slice_t ident_t;
|
| 8 |
|
| 9 |
struct decl {
|
| 10 |
ident_t name;
|
| 11 |
type_t *type;
|
| 12 |
expr_t *expr;
|
| 13 |
} decl_t;
|
| 14 |
|
| 15 |
struct expr {
|
| 16 |
enum {
|
| 17 |
EXPR_APP,
|
| 18 |
EXPR_LAM,
|
| 19 |
EXPR_LET,
|
| 20 |
EXPR_VAR,
|
| 21 |
EXPR_LIT
|
| 22 |
} tag;
|
| 23 |
} expr_t;
|
| 24 |
|
| 25 |
char* str_of_slice(slice_t);
|
| 26 |
|
| 27 |
/* expr constructors */
|
| 28 |
expr_t* mk_app(expr_t*, expr_t*);
|
| 29 |
expr_t* mk_lam(ident_t*, expr_t*);
|
| 30 |
expr_t* mk_let(ident_t*, expr_t*, expr_t*);
|
| 31 |
expr_t* mk_var(ident_t*);
|
| 32 |
expr_t* mk_annot(expr_t*, type_t*);
|
| 33 |
expr_t* mk_lit_int(ident_t*);
|
| 34 |
expr_t* mk_lit_float(ident_t*);
|
| 35 |
expr_t* mk_lit_char(ident_t*);
|
| 36 |
expr_t* mk_lit_str(ident_t*);
|
| 1 |
enum token {
|
| 2 |
TOK_LIDENT,
|
| 3 |
TOK_UIDENT,
|
| 4 |
TOK_STRING,
|
| 5 |
TOK_CHAR,
|
| 6 |
TOK_INT,
|
| 7 |
|
| 8 |
TOK_LPAR,
|
| 9 |
TOK_RPAR,
|
| 10 |
TOK_LBRAC,
|
| 11 |
TOK_RBRAC,
|
| 12 |
TOK_LCURL,
|
| 13 |
TOK_RCURL,
|
| 14 |
TOK_ARROW,
|
| 15 |
TOK_IDENT,
|
| 16 |
};
|
| 1 |
-- this is just a normal type definition
|
| 2 |
record Monoid m =
|
| 3 |
{ .mempty m
|
| 4 |
, .mappend (m -> m -> m)
|
| 5 |
}
|
| 6 |
|
| 7 |
implicit monoidIntAdd : Monoid Int =
|
| 8 |
{ .mempty = 0
|
| 9 |
, .mappend = (+)
|
| 10 |
}
|
| 11 |
|
| 12 |
monoidIntMul : Monoid Int =
|
| 13 |
{ .mempty = 1
|
| 14 |
, .mappend = (*)
|
| 15 |
}
|
| 16 |
|
| 17 |
mconcat (implicit m : Monoid m) (lst : List m) : m =
|
| 18 |
case lst of
|
| 19 |
Cons x xs -> m.mappend x xs
|
| 20 |
Nil -> m.mempty
|
| 21 |
|
| 22 |
main = print (mconcat monoidIntAdd [1,2,3])
|
| 23 |
; print (mconcat monoidIntMul [1,2,3])
|
| 24 |
; print (mconcat [1,2,3])
|
| 1 |
record Add x =
|
| 2 |
{ .zero x
|
| 3 |
, .add (x -> x -> x)
|
| 4 |
}
|
| 5 |
|
| 6 |
record Mul x =
|
| 7 |
{ .one x
|
| 8 |
, .mul (x -> x -> x)
|
| 9 |
}
|
| 10 |
|
| 11 |
sum (implicit add : Add a) = foldl add.zero add.add
|
| 12 |
prod (implicit mul : Mul a) = foldl mul.one mul.mul
|