{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, TypeSynonymInstances, NoMonomorphismRestriction, FlexibleContexts, FunctionalDependencies, ScopedTypeVariables, TypeOperators, OverlappingInstances, IncoherentInstances #-} module Control (Control(..), TypeOf(..) ,app1,app2,app3,app4 ,lam1,lam2,lam3,lam4 ) where import Data import Struct import Type type VarName = String {- Control. First order language with lexical scope and tail calls, no recursion. a,b,... values t value, global return type f,g,... functions This turns out to be an embedding of the simply typed lambda calculus with constraints on reference and return types. Control uses the Struct class, which abstracts data structures. -} class Data m r => Control m r | r -> m, m -> r where -- Conditional branching ifte :: DataWord t => r Tbool -> m (r t) -> m (r t) -> m (r t) -- Recursive function definitions (loops) letrec :: (r f -> m (r f)) -- body with open recursion -> (r f -> m (r t)) -- scope with functions defined -> m (r t) -- Function abstraction and application. The language is first -- order so we need a way to compose multiple arguments into one. -- We don't care about the return type of functions since we only -- use CPS / tail calls. -- StructVar is for variable name generation in Code. FIXME: can it -- be moved elsewhere? lam :: (DataWord s, StructVar sr, Struct r s sr) => (sr -> m (r t)) -> m (r (s -> m t)) app :: (DataWord s, Struct r s sr) => r (s -> m t) -> sr -> m (r t) -- Application exit. I.e. for embedding in C we need a single -- return value to pass to the parent continuation. ret :: r a -> m (r a) -- Toplevel definition. FIXME: This probably shouldn't be part of -- Control. Maybe use a separate Toplevel class? def :: TypeOf (r t) => String -> m (r t) -> m (r ()) -- TODO: For now these will work, but try to abstract these in a class. app1 f a1 = app f (L a1) app2 f a1 a2 = app f ((,) (L a1) (L a2)) app3 f a1 a2 a3 = app f ((,) (L a1) ((,) (L a2) (L a3))) app4 f a1 a2 a3 a4 = app f ((,) (L a1) ((,) (L a2) ((,) (L a3) (L a4)))) lam1 f = lam $ \(L a1) -> f a1 lam2 f = lam $ \((,) (L a1) (L a2)) -> f a1 a2 lam3 f = lam $ \((,) (L a1) ((,) (L a2) (L a3))) -> f a1 a2 a3 lam4 f = lam $ \((,) (L a1) ((,) (L a2) ((,) (L a3) (L a4)))) -> f a1 a2 a3 a4 -- Compilation requires a standard way to convert a term to a run-time -- representation of its type. The main point of this class is to -- handle the representation (r) wrapping of DataWord, and provide a -- way to get the return type of Control functions (_lambda). -- These are overlapping instances, but that seems to work OK (for now). class TypeOf t where typeOf :: t -> Type instance DataWord t => TypeOf (r t) where typeOf _ = primType (undefined :: t) instance (Data m r, TypeOf (r o)) => TypeOf (r (i -> m o)) where typeOf _ = typeOf (undefined :: (r o))