ad-hoc-poly is an implementation of type classes.
ad-hoc-poly works as a transpiler to OCaml. There are two source languages named mlx1 and mlx2.
To see how this works, save the code below as sample.mlx2:
class<T> Num {
add :: T -> T -> T,
mul :: T -> T -> T,
neg :: T -> T,
} in
impl Num<Int> {
add = add_int,
mul = mul_int,
neg = neg_int,
} in
impl Num<Float> {
add = add_float,
mul = mul_float,
neg = neg_float,
} in
let square = \x. mul x x in
let x = add (square 3) (int_of_float (square 2.7)) in
print_int xAnd perform translation with:
stack run mlx2 -- sample.mlx2You can find more examples under test/data. Also, you can configure the type environment by editing env.yaml. Enjoy!
mlx1 is a language with type classes. A type-directed translation pass resolves overloadings and compiles mlx1 into well-typed OCaml code.
mlx2 is a language with a syntax like Rust's traits. mlx2 is desugared to mlx1.
A. Currently, No.
See #1.
A. You can use forall for ∀ and \ for λ and Λ.
A. To separate two compilation phases.
To perform the dictionary conversion, it is needed to identify each class declaration.
class and instance declarations take type expressions to represent constraints and instantiations in Haskell-like syntax. Thus, a type evaluation is required to identify the class declarations. I don't want this because the translation from mlx1 to OCaml also requires type evaluation.
class and impl declarations in mlx2 syntax take class names as a simple identifier and I can implement dictionary conversion easily because of it.
Q. Is it necessary to introduce type-level lambda like this implementation to implement type classes?
A. No.
Haskell is one of the major conterexamples.
A. No.
A. Yes.
I've implemented this as two-pass compilation just for simplicity.
A. No.
- Wadler, Philip, and Stephen Blott. "How to make ad-hoc polymorphism less ad hoc." Proceedings of the 16th ACM SIGPLAN-SIGACT symposium on Principles of programming languages. ACM, 1989.