packages feed

idris-0.1.3: Idris/SCTrans.lhs

> {-# OPTIONS_GHC -fglasgow-exts #-}

Transformations at the supercombinator level.

Includes transforming data types into special case more efficient versions.
e.g. Nat -> Int, possibly List -> Block of memory, etc.

NOTE: Anything which has the shape of Nat, e.g. Fin could be converted to Nat 
at an earlier stage, e.g. in ConTrans phase, then these transformations
would take effect.

> module Idris.SCTrans(transformSC, applyTransformsSC, SCTrans(..)) where

> import Idris.AbsSyntax
> import Idris.LambdaLift

> import Ivor.TT

> import Maybe
> import Debug.Trace

> data SCTrans = SCTrans String (SCBody -> SCBody)

> allSCTrans = [cfold, natCons, natCase, boolCons, boolCase, natArith, cfold]

Easier to take 'erasure' as an argument here - don't do constructor
transformations if we're not doing erasure (could do others).

> transformSC :: Bool -> SCFun -> SCFun
> transformSC erasure (SCFun c ns b) = SCFun c ns (tr b) where
>     tr tm = if erasure then applyTransformsSC allSCTrans tm
>                else tm

> applyTransformsSC :: [SCTrans] -> SCBody -> SCBody
> applyTransformsSC ts tm = foldl (flip doTrans) tm ts

Built-in transformations.

* Constant folding

> cfold = SCTrans "Constant Folding" con where
>    con (SInfix op (SConst (Num x)) (SConst (Num y)))
>        | Just r <- runOp op x y = SConst (Num r)
>    con x = x
>    runOp Plus x y = Just $ x+y
>    runOp Minus x y = Just $ x-y
>    runOp Times x y = Just $ x*y
>    runOp Divide x y = Just $ x `div` y
>    runOp _ x y = Nothing

* Nat constructors

> natCons = SCTrans "NatCons" ncon where
>    ncon (SApp (SCon succ t) [arg]) 
>           | succ == name "S" = SInfix Plus (SConst (Num 1)) arg
>    ncon (SCon zero t) 
>           | zero == name "O" = SConst (Num 0)
>    ncon x = x

* Nat function special cases

> natArith = SCTrans "NatArith" narith where
>    narith (SApp (SVar op) [x,y]) 

Arithmetic can use machine operations

>           | op == name "plus" = SInfix Plus x y
>           | op == name "mult" = SInfix Times x y

Conversions between nat and int are just no-ops

>    narith (SApp (SVar op) [x]) 
>           | op == name "natToInt" = x
>           | op == name "intToNat" = x

>    narith x = x

* Nat destructor (case)

> natCase = SCTrans "NatCase" ncase where
>    ncase x@(SCCase t alts) 
>     = case getNatAlts alts of
>              (Just z, Just (arg, s), _) -> mkNatRHS t z (doSuc arg t s)
>              (Just z, Nothing, Just d) -> mkNatRHS t z d
>              (Nothing, Just (arg, s), Just d) -> mkNatRHS t d (doSuc arg t s)
>              (Nothing, Nothing, Just d) -> x
>              _ -> x
>    ncase x = x

if t==0 then z else s

>    mkNatRHS t z s = SIfZero t z s

let arg = t - 1 in s

>    doSuc arg t s = SLet arg (SInfix Minus t (SConst (Num 1))) s

>    getNatAlts alts = let zs = mHead (mapMaybe getZeroAlt alts)
>                          ss = mHead (mapMaybe getSuccAlt alts)
>                          defs = mHead (mapMaybe getDefault alts) in
>                                 (zs, ss, defs)
>                 
>    mHead [x] = Just x
>    mHead [] = Nothing
>    getZeroAlt (SAlt zero t [] zrhs) 
>                 | zero == name "O" = return zrhs
>    getZeroAlt _ = fail "no O"
>    getSuccAlt (SAlt succ t [arg] srhs) 
>                 | succ == name "S" = return (arg, srhs)
>    getSuccAlt _ = fail "no S"
>    getDefault (SDefault drhs) = return drhs
>    getDefault _ = fail "no default"


[SAlt zero t [] zrhs]]
[SAlt succ t [arg] shrs]
[SAlt zero t [] zrhs, SAlt succ t [arg] shrs, _]

* Bool constructors

> boolCons = SCTrans "BoolCons" ncon where
>    ncon (SCon true t)
>           | true == name "True" = SConst (Num 1)
>    ncon (SCon false t) 
>           | false == name "False" = SConst (Num 0)
>    ncon x = x

* Bool destructor (case)

> boolCase = SCTrans "BoolCase" bcase where
>    bcase x@(SCCase t alts) 
>     = case getBoolAlts alts of
>              (Just fc, Just tc, _) -> mkBoolRHS t fc tc
>              (Just fc, Nothing, Just d) -> mkBoolRHS t fc d
>              (Nothing, Just tc, Just d) -> mkBoolRHS t d tc
>              (Nothing, Nothing, Just d) -> x
>              _ -> x
>    bcase x = x

>    mkBoolRHS t z s = SIfZero t z s

>    getBoolAlts alts = let fs = mHead (mapMaybe getFalseAlt alts)
>                           ts = mHead (mapMaybe getTrueAlt alts)
>                           defs = mHead (mapMaybe getDefault alts) in
>                                  (fs, ts, defs)
>                 
>    mHead [x] = Just x
>    mHead [] = Nothing

>    getFalseAlt (SAlt false t [] frhs) 
>                 | false == name "False" = return frhs
>    getFalseAlt _ = fail "no O"
>    getTrueAlt (SAlt true t [] trhs) 
>                 | true == name "True" = return trhs
>    getTrueAlt _ = fail "no True"
>    getDefault (SDefault drhs) = return drhs
>    getDefault _ = fail "no default"

> doTrans :: SCTrans -> SCBody -> SCBody
> doTrans (SCTrans _ trans) tm = tr tm where
>     tr (SApp b bs) = trans (SApp (tr b) (map tr bs))
>     tr (SLet n v sc) = trans (SLet n (tr v) (tr sc))
>     tr (SCCase b alts) = trans (SCCase (tr b) (map tralt alts))
>     tr (SInfix op l r) = trans (SInfix op (tr l) (tr r))
>     tr (SLazy s) = trans (SLazy (tr s))
>     tr (SIf i t e) = trans (SIf (tr i) (tr t) (tr e))
>     tr (SIfZero i t e) = trans (SIfZero (tr i) (tr t) (tr e))
>     tr s = trans s

>     tralt (SAlt n t args rhs) = SAlt n t args (tr rhs)
>     tralt (SConstAlt c rhs) = SConstAlt c (tr rhs)
>     tralt (SDefault rhs) = SDefault (tr rhs)