Home

Awesome

Typeclass.jl

Build Status

Multiparameter typeclasses for Julia. Allows circular definitions, interfaces, and so on.

To use it, define a class by giving some methods, which can either have an output type or default implementation. Here is an example with only output types:

@class Monoid T begin
       munit(::T)::T
       mappend(x::T,y::T)::T
end

The constructor macro @class takes the name of the typeclass, followed by any number of type parameters separated by spaces, then a begin-end block containing the methods (which use the type parameters).

Now declare some type, or ordered list of types, to be an instance of the class, supplying any needed methods.

@instance Monoid Array{Int} begin
       munit(::Array{Int})=Int[]
       mappend(x::Array{Int},y::Array{Int})=[x;y]
end
    
@test munit(Int[3])==Int[]
@test mappend([3,4],[4,5])==[3,4,4,5]

Circular definitions are fine. They are resolved by Typeclass.jl once you give the instance declaration, and you only need to supply enough information to disambiguate (e.g. defining eq or noteq below is enough).

@class Eq T begin
    eq(x::T,y::T)=!noteq(x,y)
    noteq(x::T,y::T)=!eq(x,y)
    ==(x::T,y::T)=eq(x,y) # ignored unless use @instance! form
end

Note that

@instance

does NOT override any methods that are already able to operate on your type, while

@instance!

does register a new method.

More complex example: a monoidal category

@class MonoidalCategory Ob Mor begin
    dom(f::Mor)::Ob
    cod(f::Mor)::Ob
    id(A::Ob)::Mor
    compose(f::Mor,g::Mor)::Mor #f*g
    otimes(f::Mor,g::Mor)::Mor
    otimes(A::Ob,B::Ob)::Ob
    munit(::Ob)::Ob
    munit(f::Mor)=munit(dom(f))
    # syntax, using unicode
    ∘(f::Mor,g::Mor)=compose(f,g)
    ⊗(f::Mor,g::Mor)=otimes(f,g)
    ⊗(A::Ob,B::Ob)=otimes(A,B)
end

Now we can tell Julia how to treat matrices as a monoidal category.

typealias Mat Matrix{Float64}
@instance MonoidalCategory Int Mat begin
    dom(f::Mat)=size(f)[2]
    cod(f::Mat)=size(f)[1]
    id(A::Int)=eye(A)
    compose(f::Mat,g::Mat)=f*g
    otimes(f::Mat,g::Mat)=kron(f,g)
    otimes(A::Int,B::Int)=A*B
    munit(::Int)=1
end

@test id(2)⊗id(2) == id(4)
@test id(2)∘id(2) == id(2)
@test dom(rand(2,3))==3