--
-- (c) Susumu Katayama
--
CoreLang.lhs
extracted haskell-src-free stuff that can be used with Hat.
(This looks like Bindging.hs....)
\begin{code}
#ifndef __GLASGOW_HASKELL__
#endif
module MagicHaskeller.CoreLang where
import Language.Haskell.TH
import Data.Array
import Debug.Trace
import qualified MagicHaskeller.PolyDynamic as PD
import Data.Char(chr,ord,isDigit)
import MagicHaskeller.TyConLib
import MagicHaskeller.ReadTHType(thTypeToType)
#ifdef FORCE
import Control.Parallel.Strategies
#endif
import Data.Bits
import Data.Function(fix)
import Data.Int
import Data.Word
import Data.List(genericLength, genericIndex)
infixl :$
type Var = Int16
data CoreExpr = S | K | I | B | C | S' | B' | C' | Y
| Lambda CoreExpr | X !Int8
| FunLambda CoreExpr | FunX Int
| Tuple !Int8
| Primitive {primId :: !Var}
| PrimCon {primId :: !Var}
| Context Dictionary
| CoreExpr :$ CoreExpr
| Case CoreExpr [(Var,Int8,CoreExpr)]
| Fix CoreExpr Int8 [Int8]
| VarName String
deriving (Eq, Show, Ord)
newtype Dictionary = Dict {undict :: PD.Dynamic} deriving (Show)
instance Ord Dictionary where
compare _ _ = EQ
instance Eq Dictionary where
_ == _ = True
#ifdef FORCE
instance NFData CoreExpr where
rnf (Lambda e) = rnf e
rnf (X i) = rnf i
rnf (Tuple i) = rnf i
rnf (Primitive _) = ()
rnf (c :$ d) = rnf c `seq` rnf d
rnf e = ()
#endif
isAbsent :: Int -> CoreExpr -> Bool
isAbsent numArgs expr = isa (2^numArgs 1) expr /= 0
isa :: Integer -> CoreExpr -> Integer
isa bits (X n) = clearBit bits $ fromIntegral n
isa bits (Lambda e) = isa (bits `unsafeShiftL` 1) e `unsafeShiftR` 1
isa bits (f :$ e ) = isa (isa bits f) e
isa bits Primitive{} = bits
isa bits PrimCon{} = bits
isa bits Context{} = bits
#if __GLASGOW_HASKELL__ < 710
instance Ord Exp where
compare (VarE n0) (VarE n1) = n0 `compare` n1
compare (VarE n0) _ = LT
compare (ConE n0) (VarE n1) = GT
compare (ConE n0) (ConE n1) = n0 `compare` n1
compare (ConE n0) _ = LT
compare (AppE _ _) (VarE _) = GT
compare (AppE _ _) (ConE _) = GT
compare (AppE e0 f0) (AppE e1 f1) = case compare e0 e1 of EQ -> compare f0 f1
c -> c
compare (AppE _ _) _ = LT
compare a b = show a `compare` show b
#endif
instance Read Exp where
readsPrec _ str = [(error "ReadS Exp is not implemented yet", str)]
type VarLib = Array Var PD.Dynamic
actualVarName :: String -> Exp
actualVarName = VarE . mkName . stripByd_
stripByd_ ('b':'y':d:'_':name) | isDigit d = name
stripByd_ ('-':'-':'#':name) = dropWhile (=='#') name
stripByd_ name = name
exprToTHExp, exprToTHExpLite :: VarLib -> CoreExpr -> Exp
exprToTHExp vl e = exprToTHExp' True vl $ lightBeta e
exprToTHExpLite vl e = exprToTHExp' False vl $ lightBeta e
exprToTHExp' pretty vl e = x2hsx (fromIntegral $ ord 'a'1 :: Int8) (ord 'a' 1) e
where x2hsx :: Int8 -> Int -> CoreExpr -> Exp
x2hsx dep fdep (Lambda e) =
case x2hsx (dep+1) fdep e of LamE pvars expr -> LamE (pvar:pvars) expr
expr -> LamE [pvar] expr
where var = mkName [chr $ fromIntegral (dep+1)]
pvar | not pretty || 0 `occursIn` e = VarP var
| otherwise = WildP
x2hsx dep fdep (FunLambda e) =
case x2hsx dep (fdep+1) e of LamE pvars expr -> LamE (pvar:pvars) expr
expr -> LamE [pvar] expr
where var = mkName ['f',chr (fdep+1)]
pvar | not pretty || 0 `funOccursIn` e = VarP var
| otherwise = WildP
x2hsx dep fdep (X n) = VarE (mkName [chr $ fromIntegral (dep n :: Int8)])
x2hsx dep fdep (FunX n) = VarE (mkName ['f', chr $ fromIntegral (fdep n)])
x2hsx _ _ (Primitive n) = x2hsxPrim n
x2hsx _ _ (PrimCon n) = x2hsxPrim n
x2hsx dep fdep (p@(Primitive _) :$ e :$ e0 :$ e1) | hdIsCxt e = x2hsxPrim3 dep fdep p e0 e1
x2hsx dep fdep (p@(PrimCon _) :$ e :$ e0 :$ e1) | hdIsCxt e = x2hsxPrim3 dep fdep p e0 e1
x2hsx dep fdep (p@(Primitive _) :$ e0 :$ e1) = x2hsxPrim3 dep fdep p e0 e1
x2hsx dep fdep (p@(PrimCon _) :$ e0 :$ e1) = x2hsxPrim3 dep fdep p e0 e1
x2hsx dep fdep (Y :$ FunLambda e) = case x2hsx dep fdep (FunLambda e) of LamE [WildP] expr -> expr
LamE (WildP:pvs) expr -> LamE pvs expr
expr -> VarE 'fix `AppE` expr
x2hsx dep fdep (Y :$ Lambda e) = case x2hsx dep fdep (Lambda e) of LamE [WildP] expr -> expr
LamE (WildP:pvs) expr -> LamE pvs expr
expr -> VarE 'fix `AppE` expr
x2hsx dep fdep (e0 :$ e1) | hdIsCxt e1 = x2hsx dep fdep e0
| otherwise = x2hsx dep fdep e0 `AppE` x2hsx dep fdep e1
x2hsx dep fdep (Case ce ts) = CaseE (x2hsx dep fdep ce) (map (tsToMatch dep fdep) ts)
x2hsx dep fdep (Fix ce n is)
= case x2hsx dep fdep (FunLambda (napply (fromIntegral n) Lambda ce)) of
LamE (WildP:ps) e -> foldl AppE (LamE ps e) $ map (x2hsx dep fdep . X) is
LamE (VarP name : ps) (CaseE (VarE n) ms)
| VarP n `elem` ps -> LetE [FunD name (map (\(Match p b decls) -> Clause (map (replacePat n p) ps) b decls) ms)]
(foldl AppE (VarE name) $ map (x2hsx dep fdep . X) is)
LamE (VarP name : ps) e -> LetE [FunD name [Clause ps (NormalB e) []]]
(foldl AppE (VarE name) $ map (x2hsx dep fdep . X) is)
x2hsx dep _ (VarName str) = VarE (mkName str)
x2hsx _ _ Y = VarE 'fix
x2hsx _ _ K = VarE 'const
x2hsx _ _ B = VarE '(.)
x2hsx _ _ C = VarE 'flip
x2hsx _ _ S = VarE $ mkName "ap"
x2hsx _ _ I = VarE 'id
x2hsx _ _ S' = VarE $ mkName "sprime"
x2hsx _ _ B' = VarE $ mkName "bprime"
x2hsx _ _ C' = VarE $ mkName "cprime"
x2hsx _ _ e = error ("exprToTHExp: converting " ++ show e)
x2hsxPrim n = case PD.dynExp (vl ! n) of
ConE name -> ConE $ mkName $ nameBase name
VarE name -> actualVarName $ nameBase name
e -> e
x2hsxPrim3 dep fdep p e0 e1
| hdIsCxt e0 = x2hsx dep fdep (p :$ e1)
| otherwise
= let hsx0 = x2hsx dep fdep e0
hsx1 = x2hsx dep fdep e1
n = primId p
in case PD.dynExp (vl!n) of
e@(VarE name) | head base `elem` "!@#$%&*+./<=>?\\^|-~"
-> InfixE (Just hsx0) (actualVarName base) (Just hsx1)
| otherwise -> (actualVarName base `AppE` hsx0) `AppE` hsx1
where base = nameBase name
e@(ConE name) | namestr == ":" -> case hsx1 of ListE hsxs -> ListE (hsx0 : hsxs)
ConE n | nameBase n == "[]" -> ListE [hsx0]
_ -> InfixE (Just hsx0) (ConE $ mkName ":") (Just hsx1)
| head namestr == ':' -> InfixE (Just hsx0) (ConE $ mkName namestr) (Just hsx1)
| otherwise -> (ConE (mkName namestr) `AppE` hsx0) `AppE` hsx1
where
namestr = nameBase name
e -> (e `AppE` hsx0) `AppE` hsx1
hdIsCxt (Context{}) = True
hdIsCxt (e :$ _) = hdIsCxt e
hdIsCxt _ = False
replacePat name new (VarP o) | o==name = AsP name new
replacePat _ _ old = old
tsToMatch dep fdep (ctor, arity, expr)
= case PD.dynExp (vl ! ctor) of
ConE name -> case x2hsx dep fdep (napply arint Lambda expr) of
LamE pvars ex -> case compare (length pvars) arint of
LT -> error "too few lambda abstractions in Case...can't happen!"
EQ -> Match (mkPat nameb pvars) (NormalB ex) []
GT -> Match (mkPat nameb tk) (NormalB $ LamE dr ex) []
where (tk,dr) = splitAt arint pvars
ex
| otherwise -> Match (ConP (mkName nameb) []) (NormalB ex) []
where nameb = nameBase name
arint = fromIntegral arity
mkPat ":" [pv1,pv2] = InfixP pv1 (mkName ":") pv2
mkPat (':':_) [pv1,pv2] = InfixP pv1 (mkName nameb) pv2
mkPat nmb pvs = ConP (mkName nameb) pvs
VarE name | nameBase name == "succ" ->
case x2hsx (dep+1) fdep expr of
ex -> Match (VarP succn) (GuardedB [(NormalG (InfixE (Just $ VarE succn) (VarE $ mkName ">") (Just $ LitE $ IntegerL 0)),ex)]) [ValD (VarP name) (NormalB (InfixE (Just $ VarE succn) (VarE $ mkName "-") (Just $ LitE (IntegerL 1)))) []]
where str = [chr $ fromIntegral (dep+1)]
name = mkName str
succn = mkName ("succ"++str)
| nameBase name == "negate" ->
case x2hsx (dep+1) fdep expr of
ex -> Match (VarP negn) (GuardedB [(NormalG (InfixE (Just $ VarE negn) (VarE $ mkName "<") (Just $ LitE $ IntegerL 0)),ex)]) [ValD (VarP name) (NormalB ((VarE 'negate) `AppE` (VarE negn))) []]
where str = [chr $ fromIntegral (dep+1)]
name = mkName str
negn = mkName ("neg"++str)
LitE lit -> Match (LitP lit) (NormalB $ x2hsx dep fdep expr) []
e -> error (pprint e ++ " : non-constructor where a constructor is expected.")
n `occursIn` Lambda e = succ n `occursIn` e
n `occursIn` FunLambda e = n `occursIn` e
n `occursIn` X m = n==m
n `occursIn` (f :$ e) = (n `occursIn` f) || (n `occursIn` e)
n `occursIn` Case x ts = n `occursIn` x || any (\(_,a,ce) -> (n+a) `occursIn` ce) ts
n `occursIn` Fix e m is = n `elem` is || (n+m) `occursIn` e
_ `occursIn` _ = False
n `funOccursIn` Lambda e = n `funOccursIn` e
n `funOccursIn` FunLambda e = succ n `funOccursIn` e
n `funOccursIn` FunX m = n==m
n `funOccursIn` (f :$ e) = (n `funOccursIn` f) || (n `funOccursIn` e)
n `funOccursIn` Case x ts = n `funOccursIn` x || any (\(_,a,ce) -> n `funOccursIn` ce) ts
n `funOccursIn` Fix e _ _ = succ n `funOccursIn` e
_ `funOccursIn` _ = False
lightBeta :: CoreExpr -> CoreExpr
lightBeta (Fix e m is) | 0 `funOccursIn` e = Fix (lightBeta e) m is
| otherwise = liftFun 0 $ nlift 0 m $ foldr ($) (lightBeta e) $ zipWith replace [m1,m2..0] $ map (m+) is
lightBeta (Lambda e) = Lambda $ lightBeta e
lightBeta (FunLambda e) = FunLambda $ lightBeta e
lightBeta (Lambda e :$ X n) = lightBeta $ nlift 0 1 $ replace 0 n e
lightBeta (f :$ e) = lightBeta f :$ lightBeta e
lightBeta (Case x ts) = Case (lightBeta x) (map (\(c,a,ce) -> (c,a,lightBeta ce)) ts)
lightBeta e = e
replace o n e@(X i) | i==o = X n
replace o n (Lambda e) = Lambda (replace (succ o) (succ n) e)
replace o n (FunLambda e) = FunLambda $ replace o n e
replace o n (f :$ e) = replace o n f :$ replace o n e
replace o n (Case x ts) = Case (replace o n x) (map (\(c,a,ce) -> (c,a,replace (o+a) (n+a) ce)) ts)
replace o n (Fix e m is) = Fix (replace (o+m) (n+m) e) m (map (\x -> if x==o then n else x) is)
replace o n e = e
liftFun th (FunX i) | th<i = FunX (pred i)
liftFun th (Lambda e) = Lambda (liftFun th e)
liftFun th (FunLambda e) = FunLambda (liftFun (succ th) e)
liftFun th (f :$ e) = liftFun th f :$ liftFun th e
liftFun th (Case x ts) = Case (liftFun th x) (map (\(c,a,ce) -> (c,a,liftFun th ce)) ts)
liftFun th (Fix e m is) = Fix (liftFun (succ th) e) m is
liftFun _ e = e
nlift :: Int8 -> Int8 -> CoreExpr -> CoreExpr
nlift th n (X i) | th<i = X (in)
nlift th n (Lambda e) = Lambda (nlift (succ th) n e)
nlift th n (FunLambda e) = FunLambda (nlift th n e)
nlift th n (f :$ e) = nlift th n f :$ nlift th n e
nlift th n (Case x ts) = Case (nlift th n x) (map (\(c,a,ce) -> (c,a,nlift (th+a) n ce)) ts)
nlift th n (Fix e m is) = Fix (nlift (th+m) n e) m (map (nliftInt th n) is)
nlift th n e = e
nliftInt :: Int8 -> Int8 -> Int8 -> Int8
nliftInt th n i | th < i = in
| otherwise = i
napply n f x = iterate f x `genericIndex` n
isObviouslyBoring :: Exp -> Bool
isObviouslyBoring = iOB []
iOB patss (LamE pats expr) = iOB (reverse pats:patss) expr
iOB _ (VarE _) = False
iOB _ (ConE _) = False
iOB patss (InfixE (Just e1) o (Just e2)) = iOB patss e1 || iOB patss e2
iOB patss (ListE es) = any (iOB patss) es
iOB patss (CaseE e ts) = iOB patss e || any iOBMatch ts
where iOBMatch (Match _ (NormalB ce) _) = iOB patss ce
iOBMatch (Match _ (GuardedB ts) _) = any (iOB patss . snd) ts
iOB patss ce@(AppE f e) = any (matchExp ce) patss || iOB patss f || iOB patss e
matchExp (AppE f e) (WildP:pats) = matchExp f pats
matchExp (AppE f (VarE n1)) (VarP n2:pats) = nameBase n1 == nameBase n2 && matchExp f pats
matchExp (VarE n1) [VarP n2] = nameBase n1 == nameBase n2
matchExp _ _ = False
type Primitive = (HValue, Exp, Type)
newtype HValue = HV (forall a. a)
primitivesToTCL :: [Primitive] -> TyConLib
primitivesToTCL ps = let (_,_,ts) = unzip3 ps in thTypesToTCL ts
primitivesToVL :: TyConLib -> [Primitive] -> VarLib
primitivesToVL tcl ps
= listArray (0, genericLength ps + (lenDefaultPrimitives1)) (map (\ (HV x, e, ty) -> PD.unsafeToDyn tcl (thTypeToType tcl ty) x e) ps
++ defaultPrimitives)
defaultVarLib :: VarLib
defaultVarLib = listArray (0, lenDefaultPrimitives1) defaultPrimitives
lenDefaultPrimitives = genericLength defaultPrimitives
defaultPrimitives :: [PD.Dynamic]
defaultPrimitives
= [
$(PD.dynamic [|defaultTCL|] [|()::()|]),
$(PD.dynamic [|defaultTCL|] [|(,) ::a->b->(a,b)|]),
$(PD.dynamic [|defaultTCL|] [|(,,) ::a->b->c->(a,b,c)|]),
$(PD.dynamic [|defaultTCL|] [|(,,,) ::a->b->c->d->(a,b,c,d)|]),
$(PD.dynamic [|defaultTCL|] [|(,,,,) ::a->b->c->d->e->(a,b,c,d,e)|]),
$(PD.dynamic [|defaultTCL|] [|(,,,,,) ::a->b->c->d->e->f->(a,b,c,d,e,f)|]),
$(PD.dynamic [|defaultTCL|] [|(,,,,,,)::a->b->c->d->e->f->g->(a,b,c,d,e,f,g)|]),
$(PD.dynamic [|defaultTCL|] [|Left :: a -> Either a b|]),
$(PD.dynamic [|defaultTCL|] [|Right :: b -> Either a b|]),
$(PD.dynamic [|defaultTCL|] [|Nothing :: Maybe a|]),
$(PD.dynamic [|defaultTCL|] [|Just :: a -> Maybe a|]),
$(PD.dynamic [|defaultTCL|] [|LT :: Ordering|]),
$(PD.dynamic [|defaultTCL|] [|EQ :: Ordering|]),
$(PD.dynamic [|defaultTCL|] [|GT :: Ordering|]),
$(PD.dynamic [|defaultTCL|] [|(+)::Int->Int->Int|]),
$(PD.dynamic [|defaultTCL|] [|False::Bool|]),
$(PD.dynamic [|defaultTCL|] [|True::Bool|]),
$(PD.dynamic [|defaultTCL|] [|[]::[a]|]),
$(PD.dynamic [|defaultTCL|] [|(:)::a->[a]->[a]|]),
$(PD.dynamic [|defaultTCL|] [|0::Int|]),
$(PD.dynamic [|defaultTCL|] [|succ::Int->Int|]),
$(PD.dynamic [|defaultTCL|] [|negate::Int->Int|])]
\end{code}