hs-bindgen-1.0.0.0: src-internal/HsBindgen/Backend/SHs/Translation/Common.hs
module HsBindgen.Backend.SHs.Translation.Common (
translateElimStruct
, eAppMany
, appMany
, appManyExpr
, structCon
, idiom
, lambda
, doAll
, asNaryEApp
, asNaryTApp
-- * Shift
, shiftExpr
-- * DeBruijn utilities
, reverseEnv
, idxsEnv
, idxsPairEnv
) where
import Data.Foldable qualified as Foldable
import Data.Type.Equality
import Data.Type.Nat (Plus)
import DeBruijn
import HsBindgen.Backend.Global
import HsBindgen.Backend.Hs.AST qualified as Hs
import HsBindgen.Backend.SHs.AST
import HsBindgen.Backend.SHs.AST.Expr (FBind (..))
{-------------------------------------------------------------------------------
Structs
-------------------------------------------------------------------------------}
translateElimStruct ::
(forall ctx'. t ctx' -> SExpr ctx')
-> Hs.ElimStruct t ctx
-> SExpr ctx
translateElimStruct f (Hs.ElimStruct x constr hints add k) = ECase
(EBound x)
[SAlt constr add hints (f k)]
{-------------------------------------------------------------------------------
- Internal auxiliary: derived functionality
--------------------------------------------------------------------------------}
eAppMany :: SExpr ctx -> [SExpr ctx] -> SExpr ctx
eAppMany = Foldable.foldl' EApp
-- | Apply function to many arguments
appMany :: BindgenGlobalTerm -> [SExpr ctx] -> SExpr ctx
appMany = appManyExpr . eBindgenGlobal
appManyExpr :: SExpr ctx -> [SExpr ctx] -> SExpr ctx
appManyExpr = Foldable.foldl' EApp
-- | Struct constructor
structCon :: Hs.StructCon ctx -> SExpr ctx
structCon (Hs.StructCon s) = ECon s.constr
-- | Idiom brackets
idiom :: (pure ctx -> SExpr ctx) -> (xs ctx -> SExpr ctx) -> Hs.Ap pure xs ctx -> SExpr ctx
idiom f g (Hs.Ap p xs) = Foldable.foldl'
(\ acc x -> EInfix InfixApplicative_seq acc (g x))
(EApp (eBindgenGlobal Applicative_pure) (f p))
xs
-- | Translate lambda
lambda :: (t (S ctx) -> SExpr (S ctx)) -> Hs.Lambda t ctx -> SExpr ctx
lambda f (Hs.Lambda hint t) = ELam hint (f t)
-- | Monad sequencing
doAll :: (t ctx -> SExpr ctx) -> Hs.Seq t ctx -> SExpr ctx
doAll _ (Hs.Seq []) = eBindgenGlobal Applicative_pure `EApp` EUnit
doAll f (Hs.Seq ss) = foldr1 (EInfix InfixMonad_seq) (map f ss)
-- Recognize n-ary function applications
--
-- Arguments are returned from left to right.
asNaryEApp :: SExpr ctx -> (SExpr ctx, [SExpr ctx])
asNaryEApp = go []
where
go acc (EApp f x) = go (x : acc) f
go acc e = (e, acc)
-- Recognize n-ary type applications
--
-- Arguments are returned from left to right.
asNaryTApp :: SType ctx -> (SType ctx, [SType ctx])
asNaryTApp = go []
where
go acc (TApp f x) = go (x : acc) f
go acc t = (t, acc)
{-------------------------------------------------------------------------------
Shift
--------------------------------------------------------------------------------}
-- | Shift an expression
--
-- Typically an expression needs to be shifted to accomodate newly bound
-- variables. For example, this happens when an expression is moved under a
-- lambda.
shiftExpr :: SExpr ctx -> SExpr (S ctx)
shiftExpr = shiftNExpr (AS AZ)
-- | Shift an expression @n@ times
--
-- Typically an expression needs to be shifted to accomodate newly bound
-- variables. For example, this happens when an expression is moved under a
-- lambda.
shiftNExpr :: Add n ctx ctx' -> SExpr ctx -> SExpr ctx'
shiftNExpr add = \case
EGlobal g -> EGlobal g
EBound idx -> EBound (shiftIdxN add idx)
EFree tn -> EFree tn
ECon c -> ECon c
EUnboxedIntegral i -> EUnboxedIntegral i
EIntegral i mct -> EIntegral i mct
EFloat f ct -> EFloat f ct
EDouble d ct -> EDouble d ct
ECChar c -> ECChar c
EString s -> EString s
ECString bs -> ECString bs
EApp f g -> EApp (shiftNExpr add f) (shiftNExpr add g)
EInfix io e1 e2 -> EInfix io (shiftNExpr add e1) (shiftNExpr add e2)
ELam nh e -> ELam nh (shiftNExpr (shiftAdd add) e)
EUnusedLam e -> EUnusedLam (shiftNExpr add e)
ECase e as -> ECase (shiftNExpr add e) (map (shiftNAlt add) as)
EUnit -> EUnit
EBoxedTup p -> EBoxedTup p
EUnboxedTup p -> EUnboxedTup p
EList es -> EList (fmap (shiftNExpr add) es)
ETypeApp e t -> ETypeApp (shiftNExpr add e) t
ERecCon n fbs -> ERecCon n (fmap (shiftNFBind add) fbs)
shiftAdd :: Add n ctx ctx' -> Add n (S ctx) (S ctx')
shiftAdd = shiftNAdd (AS AZ) -- equivalent to rsuccAdd
shiftNAdd :: Add n ctx1 ctx2 -> Add m ctx ctx' -> Add m (Plus n ctx) (Plus n ctx')
shiftNAdd = \case
AZ -> id
AS x -> rsuccAdd . shiftNAdd x
shiftIdxN :: Add n ctx ctx' -> Idx ctx -> Idx ctx'
shiftIdxN add idx = case add of
AZ -> idx
AS add' -> IS (shiftIdxN add' idx)
shiftNFBind :: Add n ctx ctx' -> FBind ctx -> FBind ctx'
shiftNFBind add fb = FBind {
label = fb.label
, expr = shiftNExpr add fb.expr
}
shiftNAlt :: forall n ctx ctx'. Add n ctx ctx' -> SAlt ctx -> SAlt ctx'
shiftNAlt add = \case
SAlt @m @_ @ctx'' n (a :: Add m ctx ctx'') nhs (e :: SExpr ctx'') ->
case eqSymmetry add of
Refl -> -- ctx' :~: Plus n ctx
let
a' :: Add m (Plus n ctx) (Plus n ctx'')
a' = shiftNAdd add a
add' :: Add n ctx'' (Plus n ctx'')
add' = eqReflexivity (addToSize add)
e' :: SExpr (Plus n ctx'')
e' = shiftNExpr add' e
in
SAlt n a' nhs e'
SAltNoConstr ns e ->
SAltNoConstr ns (shiftNExpr (shiftAdd add) e)
SAltUnboxedTuple a ns e ->
-- NOTE: same proof as the 'SAlt' case
case eqSymmetry add of
Refl ->
let
a' = shiftNAdd add a
add' = eqReflexivity (addToSize add)
e' = shiftNExpr add' e
in
SAltUnboxedTuple a' ns e'
-- | Symmetry of equality (roughly)
--
-- \[
-- forall n m p. n + m = p \implies p = n + m
-- \]
--
eqSymmetry :: Add n m p -> p :~: Plus n m
eqSymmetry = \case
AZ -> Refl
AS x -> case eqSymmetry x of
Refl -> Refl
-- | Reflexivity of equality (roughly)
--
-- \[
-- forall n m. n + m = n + m
-- \]
eqReflexivity :: Size n -> Add n m (Plus n m)
eqReflexivity = \case
SZ -> AZ
SS x -> lsuccAdd $ eqReflexivity x
{-------------------------------------------------------------------------------
DeBruijn utilities
--------------------------------------------------------------------------------}
-- | Reverse an 'Env'
reverseEnv :: forall ctx a. Env ctx a -> Env ctx a
reverseEnv = \env -> go (lzeroAdd (sizeEnv env)) EmptyEnv env
where
go ::
forall ctx1 ctx2 ctx3.
-- | Proof that the output environment's size is the same as the sum of
-- the two input environment's sizes
Add ctx1 ctx2 ctx3
-- | Accumulator
-> Env ctx1 a
-- | Input to reverse
-> Env ctx2 a
-> Env ctx3 a
go proof acc EmptyEnv = case unrzeroAdd proof of
Refl -> acc
go proof acc (xs :> x) = go (swapAdd proof) (acc :> x) xs
idxsEnv :: Env ctx a -> Env ctx (Idx ctx)
idxsEnv env = tabulateEnv (sizeEnv env) id
idxsPairEnv :: Env ctx a -> Env ctx (Idx ctx, a)
idxsPairEnv env = zipWithEnv (,) (idxsEnv env) env