Type classes and higher order types for haxe
Haxe
Switch branches/tags
Nothing to show
Pull request Compare This branch is 14 commits behind frabbit:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
docs
src/hots
test
.gitignore
README
commonTest.hxml
createImportAll.hxml
runImportAll.hxml
runTestsCpp.bat
runTestsCpp.hxml
runTestsCs.bat
runTestsCs.hxml
runTestsFlash.bat
runTestsFlash.hxml
runTestsJava.bat
runTestsJava.hxml
runTestsJs.bat
runTestsJs.hxml
runTestsMacro.hxml
runTestsNeko.bat
runTestsNeko.hxml
runTestsPhp.bat
runTestsPhp.hxml

README

(h)igher (o)rder (t)ype(s) and type classes for haxe
====================================================
Haxe lacks type constructor polymorphism, which is essential for the implementation of High Order Types.
To circumvent this missing piece we introduce two special abstract types "Of" and "In". "Of" is a type constructor which takes two types, the wrapper type and the inner type.
The abstract haskell type "f a" translates to the haxe type "Of<F,A>". A type class is represented by an interface and a corresponding abstract class which implements default implementations. Every type class has an abstract base class, even if there is no implementation (this may change in further revisions).

Functor translation example: haskell -> haxe
--------------------------------------------

    class Functor f where
       fmap :: (a -> b) -> f a -> f b
    
    interface Functor<F> implements hots.TC {
    	pulic function map <A,B> (A->B, f:Of<F,A>):Of<F,B>;
    }

    @:tcAbstract class FunctorAbstract<F> implements Functor<F>
    {
      public function map<A,B>(f:A->B, val:Of<F,A>):Of<F,B> return Scuts.abstractMethod()
    }


In Order to represent concrete wrapper types like Option<T> or Array<T> we use a combination of "Of" and "In". Option<T> can also be represented by Of<Option<In>, T>. Special boxing functions are needed to convert the type Option<T> into the type Of<Option<In>, T> and visa versa. This must be done to pass the type to a type class that abstracts over the container.

Example OptionFunctor:
--------------------------------------------

    // Typedef for a wrapped Option
    typedef OptionOf<A> = Of<Option<In>, A>
    
    // The concrete OptionFunctor
    class OptionFunctorImpl extends FunctorAbstract<Option<In>>
    {
      public function new () {}
      
      override public function map<A,B>(f:A->B, val:OptionOf<A>):OptionOf<B> {
        return OptionExt.map(val.unbox(), f).box();
      }
    }
    // OptionBox does the wrapping and unwrapping of Option types.
    class OptionBox 
    {
      public static inline function box <A>(m:Option<A>):OptionOf<A> return cast m
      public static inline function unbox <A>(m:OptionOf<A>):Option<A> return cast m
    }



Another important feature of type classes are constraints for type parameters. This is achieved by interface inheritance and delegation inside of the abstract class.

The class Applicative in haxe for example has the constraint that the wrapped inner type must be a Functor instance:
--------------------------------------------

    interface Applicative<M> implements Functor<M>, implements TC
    {
      public function ret<A>(x:A):Of<M,A>;
    
      public function apply<A,B>(f:Of<M,A->B>, val:Of<M,B>):Of<M,B>;
      
      public function thenRight<A,B>(val1:Of<M,A>, val2:Of<M,B>):Of<M,B>;
      
      public function thenLeft<A,B>(val1:Of<M,A>, val2:Of<M,B>):Of<M,A>;
    }
    
    @:tcAbstract class ApplicativeAbstract<M> implements Applicative<M>
    {
      // constraint
      var functor:Functor<M>;
      
      // constraint delegation
      @:final public inline function map<A,B>(f:A->B, val:Of<M,A>):Of<M,B> return functor.map(f, val)
      
      function new (functor:Functor<M>) { this.functor = functor; }
      
      // functions 
      public function ret<A>(x:A):Of<M,A> return Scuts.abstractMethod()
      public function apply<A,B>(f:Of<M,A->B>, val:Of<M,B>):Of<M,B> return Scuts.abstractMethod()
      public function thenRight<A,B>(val1:Of<M,A>, val2:Of<M,B>):Of<M,B> return val2
      public function thenLeft<A,B>(val1:Of<M,A>, val2:Of<M,B>):Of<M,A> return val1
    }