{-# LANGUAGE
BangPatterns,
CPP,
LambdaCase,
OverloadedStrings,
PatternSynonyms,
RankNTypes,
ScopedTypeVariables,
TupleSections,
ViewPatterns
#-}
{-# OPTIONS_GHC
-O
-fno-warn-name-shadowing
-fno-warn-unused-matches
#-}
module Dhall.Eval (
Env(..)
, Names(..)
, Closure(..)
, VChunks(..)
, Val(..)
, Void
, inst
, eval
, conv
, convEmpty
, quote
, nf
, nfEmpty
, Dhall.Eval.alphaNormalize
) where
#if MIN_VERSION_base(4,8,0)
#else
import Control.Applicative (Applicative(..), (<$>))
#endif
import Data.Foldable (foldr', foldl', toList)
import Data.List.NonEmpty (NonEmpty(..), cons)
import Data.Semigroup (Semigroup(..))
import Data.Sequence (Seq)
import Data.Text (Text)
import Dhall.Core (
Expr(..)
, Binding(..)
, Chunks(..)
, Const(..)
, Import
, Var(..)
, denote
)
import Dhall.Map (Map)
import Dhall.Set (Set)
import GHC.Natural (Natural)
import Unsafe.Coerce (unsafeCoerce)
import qualified Data.Char
import qualified Data.List.NonEmpty
import qualified Data.Sequence
import qualified Data.Text
import qualified Dhall.Binary
import qualified Dhall.Map
import qualified Dhall.Set
import qualified Text.Printf
data Env a =
Empty
| Skip !(Env a) {-# unpack #-} !Text
| Extend !(Env a) {-# unpack #-} !Text (Val a)
data Void
coeExprVoid :: Expr Void a -> Expr s a
coeExprVoid = unsafeCoerce
{-# inline coeExprVoid #-}
errorMsg :: String
errorMsg = unlines
[ _ERROR <> ": Compiler bug "
, " "
, "An ill-typed expression was encountered during normalization. "
, "Explanation: This error message means that there is a bug in the Dhall compiler."
, "You didn't do anything wrong, but if you would like to see this problem fixed "
, "then you should report the bug at: "
, " "
, "https://github.com/dhall-lang/dhall-haskell/issues "
]
where
_ERROR :: String
_ERROR = "\ESC[1;31mError\ESC[0m"
data Closure a = Cl !Text !(Env a) !(Expr Void a)
data VChunks a = VChunks ![(Text, Val a)] !Text
instance Semigroup (VChunks a) where
VChunks xys z <> VChunks [] z' = VChunks xys (z <> z')
VChunks xys z <> VChunks ((x', y'):xys') z' = VChunks (xys ++ (z <> x', y'):xys') z'
instance Monoid (VChunks a) where
mempty = VChunks [] mempty
#if !(MIN_VERSION_base(4,11,0))
mappend = (<>)
#endif
data HLamInfo a
= Prim
| Typed !Text (Val a)
| NaturalFoldCl (Val a)
| ListFoldCl (Val a)
| OptionalFoldCl (Val a)
pattern VPrim :: (Val a -> Val a) -> Val a
pattern VPrim f = VHLam Prim f
data Val a
= VConst !Const
| VVar !Text !Int
| VPrimVar
| VApp !(Val a) !(Val a)
| VLam (Val a) {-# unpack #-} !(Closure a)
| VHLam !(HLamInfo a) !(Val a -> Val a)
| VPi (Val a) {-# unpack #-} !(Closure a)
| VHPi !Text (Val a) !(Val a -> Val a)
| VBool
| VBoolLit !Bool
| VBoolAnd !(Val a) !(Val a)
| VBoolOr !(Val a) !(Val a)
| VBoolEQ !(Val a) !(Val a)
| VBoolNE !(Val a) !(Val a)
| VBoolIf !(Val a) !(Val a) !(Val a)
| VNatural
| VNaturalLit !Natural
| VNaturalFold !(Val a) !(Val a) !(Val a) !(Val a)
| VNaturalBuild !(Val a)
| VNaturalIsZero !(Val a)
| VNaturalEven !(Val a)
| VNaturalOdd !(Val a)
| VNaturalToInteger !(Val a)
| VNaturalShow !(Val a)
| VNaturalPlus !(Val a) !(Val a)
| VNaturalTimes !(Val a) !(Val a)
| VInteger
| VIntegerLit !Integer
| VIntegerShow !(Val a)
| VIntegerToDouble !(Val a)
| VDouble
| VDoubleLit !Double
| VDoubleShow !(Val a)
| VText
| VTextLit !(VChunks a)
| VTextAppend !(Val a) !(Val a)
| VTextShow !(Val a)
| VList !(Val a)
| VListLit !(Maybe (Val a)) !(Seq (Val a))
| VListAppend !(Val a) !(Val a)
| VListBuild (Val a) !(Val a)
| VListFold (Val a) !(Val a) !(Val a) !(Val a) !(Val a)
| VListLength (Val a) !(Val a)
| VListHead (Val a) !(Val a)
| VListLast (Val a) !(Val a)
| VListIndexed (Val a) !(Val a)
| VListReverse (Val a) !(Val a)
| VOptional (Val a)
| VSome (Val a)
| VNone (Val a)
| VOptionalFold (Val a) !(Val a) (Val a) !(Val a) !(Val a)
| VOptionalBuild (Val a) !(Val a)
| VRecord !(Map Text (Val a))
| VRecordLit !(Map Text (Val a))
| VUnion !(Map Text (Maybe (Val a)))
| VUnionLit !Text !(Val a) !(Map Text (Maybe (Val a)))
| VCombine !(Val a) !(Val a)
| VCombineTypes !(Val a) !(Val a)
| VPrefer !(Val a) !(Val a)
| VMerge !(Val a) !(Val a) !(Maybe (Val a))
| VField !(Val a) !Text
| VInject !(Map Text (Maybe (Val a))) !Text !(Maybe (Val a))
| VProject !(Val a) !(Either (Set Text) (Val a))
| VEmbed a
vFun :: Val a -> Val a -> Val a
vFun a b = VHPi "_" a (\_ -> b)
{-# inline vFun #-}
textShow :: Text -> Text
textShow text = "\"" <> Data.Text.concatMap f text <> "\""
where
f '"' = "\\\""
f '$' = "\\u0024"
f '\\' = "\\\\"
f '\b' = "\\b"
f '\n' = "\\n"
f '\r' = "\\r"
f '\t' = "\\t"
f '\f' = "\\f"
f c | c <= '\x1F' = Data.Text.pack (Text.Printf.printf "\\u%04x" (Data.Char.ord c))
| otherwise = Data.Text.singleton c
countName :: Text -> Env a -> Int
countName x = go (0 :: Int) where
go !acc Empty = acc
go acc (Skip env x' ) = go (if x == x' then acc + 1 else acc) env
go acc (Extend env x' _) = go (if x == x' then acc + 1 else acc) env
inst :: Eq a => Closure a -> Val a -> Val a
inst (Cl x env t) !u = eval (Extend env x u) t
{-# inline inst #-}
vVar :: Env a -> Var -> Val a
vVar env (V x (fromInteger -> i :: Int)) = go env i where
go (Extend env x' v) i
| x == x' = if i == 0 then v else go env (i - 1)
| otherwise = go env i
go (Skip env x') i
| x == x' = if i == 0 then VVar x (countName x env) else go env (i - 1)
| otherwise = go env i
go Empty i = VVar x (0 - i - 1)
vApp :: Eq a => Val a -> Val a -> Val a
vApp !t !u = case t of
VLam _ t -> inst t u
VHLam _ t -> t u
t -> VApp t u
{-# inline vApp #-}
vCombine :: Val a -> Val a -> Val a
vCombine t u = case (t, u) of
(VRecordLit m, u) | null m -> u
(t, VRecordLit m) | null m -> t
(VRecordLit m, VRecordLit m') -> VRecordLit (Dhall.Map.sort (Dhall.Map.unionWith vCombine m m'))
(t, u) -> VCombine t u
vCombineTypes :: Val a -> Val a -> Val a
vCombineTypes t u = case (t, u) of
(VRecord m, u) | null m -> u
(t, VRecord m) | null m -> t
(VRecord m, VRecord m') -> VRecord (Dhall.Map.sort (Dhall.Map.unionWith vCombineTypes m m'))
(t, u) -> VCombineTypes t u
vListAppend :: Val a -> Val a -> Val a
vListAppend t u = case (t, u) of
(VListLit _ xs, u) | null xs -> u
(t, VListLit _ ys) | null ys -> t
(VListLit t xs, VListLit _ ys) -> VListLit t (xs <> ys)
(t, u) -> VListAppend t u
{-# inline vListAppend #-}
vNaturalPlus :: Val a -> Val a -> Val a
vNaturalPlus t u = case (t, u) of
(VNaturalLit 0, u ) -> u
(t, VNaturalLit 0) -> t
(VNaturalLit m, VNaturalLit n) -> VNaturalLit (m + n)
(t, u ) -> VNaturalPlus t u
{-# inline vNaturalPlus #-}
eval :: forall a. Eq a => Env a -> Expr Void a -> Val a
eval !env t =
let
evalE :: Expr Void a -> Val a
evalE = eval env
{-# inline evalE #-}
evalChunks :: Chunks Void a -> VChunks a
evalChunks (Chunks xys z) =
foldr' (\(x, t) vcs ->
case evalE t of
VTextLit vcs' -> VChunks [] x <> vcs' <> vcs
t -> VChunks [(x, t)] mempty <> vcs)
(VChunks [] z)
xys
{-# inline evalChunks #-}
in case t of
Const k -> VConst k
Var v -> vVar env v
Lam x a t -> VLam (evalE a) (Cl x env t)
Pi x a b -> VPi (evalE a) (Cl x env b)
App t u -> vApp (evalE t) (evalE u)
Let (b :| bs) t -> go env (b:bs) where
go !env [] = eval env t
go env (b:bs) = go (Extend env (variable b)
(eval env (value b))) bs
Annot t _ -> evalE t
Bool -> VBool
BoolLit b -> VBoolLit b
BoolAnd t u -> case (evalE t, evalE u) of
(VBoolLit True, u) -> u
(VBoolLit False, u) -> VBoolLit False
(t, VBoolLit True) -> t
(t, VBoolLit False) -> VBoolLit False
(t, u) | conv env t u -> t
(t, u) -> VBoolAnd t u
BoolOr t u -> case (evalE t, evalE u) of
(VBoolLit False, u) -> u
(VBoolLit True, u) -> VBoolLit True
(t, VBoolLit False) -> t
(t, VBoolLit True) -> VBoolLit True
(t, u) | conv env t u -> t
(t, u) -> VBoolOr t u
BoolEQ t u -> case (evalE t, evalE u) of
(VBoolLit True, u) -> u
(t, VBoolLit True) -> t
(t, u) | conv env t u -> VBoolLit True
(t, u) -> VBoolEQ t u
BoolNE t u -> case (evalE t, evalE u) of
(VBoolLit False, u) -> u
(t, VBoolLit False) -> t
(t, u) | conv env t u -> VBoolLit False
(t, u) -> VBoolNE t u
BoolIf b t f -> case (evalE b, evalE t, evalE f) of
(VBoolLit True, t, f) -> t
(VBoolLit False, t, f) -> f
(b, VBoolLit True, VBoolLit False) -> b
(b, t, f) | conv env t f -> t
(b, t, f) -> VBoolIf b t f
Natural -> VNatural
NaturalLit n -> VNaturalLit n
NaturalFold -> VPrim $ \case
VNaturalLit n ->
VHLam (Typed "natural" (VConst Type)) $ \natural ->
VHLam (Typed "succ" (vFun natural natural)) $ \succ ->
VHLam (Typed "zero" natural) $ \zero ->
let go !acc 0 = acc
go acc n = go (vApp succ acc) (n - 1)
in go zero (fromIntegral n :: Integer)
n ->
VHLam (NaturalFoldCl n) $ \natural -> VPrim $ \succ -> VPrim $ \zero ->
VNaturalFold n natural succ zero
NaturalBuild -> VPrim $ \case
VHLam (NaturalFoldCl x) _ -> x
VPrimVar -> VNaturalBuild VPrimVar
t ->
t `vApp` VNatural
`vApp` VHLam (Typed "n" VNatural) (\n -> vNaturalPlus n (VNaturalLit 1))
`vApp` VNaturalLit 0
NaturalIsZero -> VPrim $ \case VNaturalLit n -> VBoolLit (n == 0)
n -> VNaturalIsZero n
NaturalEven -> VPrim $ \case VNaturalLit n -> VBoolLit (even n)
n -> VNaturalEven n
NaturalOdd -> VPrim $ \case VNaturalLit n -> VBoolLit (odd n)
n -> VNaturalOdd n
NaturalToInteger -> VPrim $ \case VNaturalLit n -> VIntegerLit (fromIntegral n)
n -> VNaturalToInteger n
NaturalShow -> VPrim $ \case VNaturalLit n -> VTextLit (VChunks [] (Data.Text.pack (show n)))
n -> VNaturalShow n
NaturalPlus t u -> vNaturalPlus (evalE t) (evalE u)
NaturalTimes t u -> case (evalE t, evalE u) of
(VNaturalLit 1, u ) -> u
(t, VNaturalLit 1) -> t
(VNaturalLit 0, u ) -> VNaturalLit 0
(t, VNaturalLit 0) -> VNaturalLit 0
(VNaturalLit m, VNaturalLit n) -> VNaturalLit (m * n)
(t, u ) -> VNaturalTimes t u
Integer -> VInteger
IntegerLit n -> VIntegerLit n
IntegerShow -> VPrim $ \case
VIntegerLit n
| 0 <= n -> VTextLit (VChunks [] (Data.Text.pack ('+':show n)))
| otherwise -> VTextLit (VChunks [] (Data.Text.pack (show n)))
n -> VIntegerShow n
IntegerToDouble -> VPrim $ \case VIntegerLit n -> VDoubleLit (read (show n))
n -> VIntegerToDouble n
Double -> VDouble
DoubleLit n -> VDoubleLit n
DoubleShow -> VPrim $ \case VDoubleLit n -> VTextLit (VChunks [] (Data.Text.pack (show n)))
n -> VDoubleShow n
Text -> VText
TextLit cs -> case evalChunks cs of
VChunks [("", t)] "" -> t
vcs -> VTextLit vcs
TextAppend t u -> evalE (TextLit (Chunks [("", t), ("", u)] ""))
TextShow -> VPrim $ \case
VTextLit (VChunks [] x) -> VTextLit (VChunks [] (textShow x))
t -> VTextShow t
List -> VPrim VList
ListLit ma ts -> VListLit (evalE <$> ma) (evalE <$> ts)
ListAppend t u -> vListAppend (evalE t) (evalE u)
ListBuild -> VPrim $ \a -> VPrim $ \case
VHLam (ListFoldCl x) _ -> x
VPrimVar -> VListBuild a VPrimVar
t ->
t `vApp` VList a
`vApp` VHLam (Typed "a" a) (\x ->
VHLam (Typed "as" (VList a)) (\as ->
vListAppend (VListLit Nothing (pure x)) as))
`vApp` VListLit (Just a) mempty
ListFold -> VPrim $ \a -> VPrim $ \case
VListLit _ as ->
VHLam (Typed "list" (VConst Type)) $ \list ->
VHLam (Typed "cons" (vFun a $ vFun list list) ) $ \cons ->
VHLam (Typed "nil" list) $ \nil ->
foldr' (\x b -> cons `vApp` x `vApp` b) nil as
as ->
VHLam (ListFoldCl as) $ \t -> VPrim $ \c -> VPrim $ \n ->
VListFold a as t c n
ListLength -> VPrim $ \ a -> VPrim $ \case
VListLit _ as -> VNaturalLit (fromIntegral (Data.Sequence.length as))
as -> VListLength a as
ListHead -> VPrim $ \ a -> VPrim $ \case
VListLit _ as -> case Data.Sequence.viewl as of
y Data.Sequence.:< _ -> VSome y
_ -> VNone a
as -> VListHead a as
ListLast -> VPrim $ \ a -> VPrim $ \case
VListLit _ as -> case Data.Sequence.viewr as of
_ Data.Sequence.:> t -> VSome t
_ -> VNone a
as -> VListLast a as
ListIndexed -> VPrim $ \ a -> VPrim $ \case
VListLit _ as -> let
a' = if null as then
Just (VRecord (Dhall.Map.fromList
[("index", VNatural), ("value", a)]))
else
Nothing
as' = Data.Sequence.mapWithIndex
(\i t -> VRecordLit
(Dhall.Map.fromList [("index", VNaturalLit (fromIntegral i)),
("value", t)]))
as
in VListLit a' as'
t -> VListIndexed a t
ListReverse -> VPrim $ \ ~a -> VPrim $ \case
VListLit t as | null as -> VListLit t (Data.Sequence.reverse as)
VListLit t as -> VListLit Nothing (Data.Sequence.reverse as)
t -> VListReverse a t
Optional -> VPrim VOptional
OptionalLit a mt -> maybe (VNone (evalE a)) (\t -> VSome (evalE t)) mt
Some t -> VSome (evalE t)
None -> VPrim $ \ ~a -> VNone a
OptionalFold -> VPrim $ \ ~a -> VPrim $ \case
VNone _ ->
VHLam (Typed "optional" (VConst Type)) $ \optional ->
VHLam (Typed "some" (vFun a optional)) $ \some ->
VHLam (Typed "none" optional) $ \none ->
none
VSome t ->
VHLam (Typed "optional" (VConst Type)) $ \optional ->
VHLam (Typed "some" (vFun a optional)) $ \some ->
VHLam (Typed "none" optional) $ \none ->
some `vApp` t
opt ->
VHLam (OptionalFoldCl opt) $ \o ->
VPrim $ \s ->
VPrim $ \n ->
VOptionalFold a opt o s n
OptionalBuild -> VPrim $ \ ~a -> VPrim $ \case
VHLam (OptionalFoldCl x) _ -> x
VPrimVar -> VOptionalBuild a VPrimVar
t -> t `vApp` VOptional a
`vApp` VHLam (Typed "a" a) VSome
`vApp` VNone a
Record kts -> VRecord (Dhall.Map.sort (evalE <$> kts))
RecordLit kts -> VRecordLit (Dhall.Map.sort (evalE <$> kts))
Union kts -> VUnion (Dhall.Map.sort ((evalE <$>) <$> kts))
UnionLit k v kts -> VUnionLit k (evalE v) (Dhall.Map.sort ((evalE <$>) <$> kts))
Combine t u -> vCombine (evalE t) (evalE u)
CombineTypes t u -> vCombineTypes (evalE t) (evalE u)
Prefer t u -> case (evalE t, evalE u) of
(VRecordLit m, u) | null m -> u
(t, VRecordLit m) | null m -> t
(VRecordLit m, VRecordLit m') ->
VRecordLit (Dhall.Map.sort (Dhall.Map.union m' m))
(t, u) -> VPrefer t u
Merge x y ma -> case (evalE x, evalE y, evalE <$> ma) of
(VRecordLit m, VUnionLit k v _, _)
| Just f <- Dhall.Map.lookup k m -> f `vApp` v
| otherwise -> error errorMsg
(VRecordLit m, VInject _ k mt, _)
| Just f <- Dhall.Map.lookup k m -> maybe f (vApp f) mt
| otherwise -> error errorMsg
(x, y, ma) -> VMerge x y ma
Field t k -> case evalE t of
VRecordLit m
| Just v <- Dhall.Map.lookup k m -> v
| otherwise -> error errorMsg
VUnion m -> case Dhall.Map.lookup k m of
Just (Just _) -> VPrim $ \ ~u -> VInject m k (Just u)
Just Nothing -> VInject m k Nothing
_ -> error errorMsg
t -> VField t k
Project t (Left ks) ->
if null ks then
VRecordLit mempty
else case evalE t of
VRecordLit kvs
| Just s <- traverse (\k -> (k,) <$> Dhall.Map.lookup k kvs) (toList ks)
-> VRecordLit (Dhall.Map.sort (Dhall.Map.fromList s))
| otherwise -> error errorMsg
t -> VProject t (Left ks)
Project t (Right e) ->
case evalE e of
VRecord kts ->
evalE (Project t (Left (Dhall.Set.fromList (Dhall.Map.keys kts))))
e' -> VProject (evalE t) (Right e')
Note _ e -> evalE e
ImportAlt t _ -> evalE t
Embed a -> VEmbed a
eqListBy :: (a -> a -> Bool) -> [a] -> [a] -> Bool
eqListBy f = go where
go (x:xs) (y:ys) | f x y = go xs ys
go [] [] = True
go _ _ = False
{-# inline eqListBy #-}
eqMapsBy :: Ord k => (v -> v -> Bool) -> Map k v -> Map k v -> Bool
eqMapsBy f mL mR = eqListBy eq (Dhall.Map.toList mL) (Dhall.Map.toList mR)
where
eq (kL, vL) (kR, vR) = kL == kR && f vL vR
{-# inline eqMapsBy #-}
eqMaybeBy :: (a -> a -> Bool) -> Maybe a -> Maybe a -> Bool
eqMaybeBy f = go where
go (Just x) (Just y) = f x y
go Nothing Nothing = True
go _ _ = False
{-# inline eqMaybeBy #-}
conv :: forall a. Eq a => Env a -> Val a -> Val a -> Bool
conv !env t t' =
let
fresh :: Text -> (Text, Val a)
fresh x = (x, VVar x (countName x env))
{-# inline fresh #-}
freshCl :: Closure a -> (Text, Val a, Closure a)
freshCl cl@(Cl x _ _) = (x, snd (fresh x), cl)
{-# inline freshCl #-}
convChunks :: VChunks a -> VChunks a -> Bool
convChunks (VChunks xys z) (VChunks xys' z') =
eqListBy (\(x, y) (x', y') -> x == x' && conv env y y') xys xys' && z == z'
{-# inline convChunks #-}
convE :: Val a -> Val a -> Bool
convE = conv env
{-# inline convE #-}
convSkip :: Text -> Val a -> Val a -> Bool
convSkip x = conv (Skip env x)
{-# inline convSkip #-}
in case (t, t') of
(VConst k, VConst k') -> k == k'
(VVar x i, VVar x' i') -> x == x' && i == i'
(VLam _ (freshCl -> (x, v, t)), VLam _ t' ) -> convSkip x (inst t v) (inst t' v)
(VLam _ (freshCl -> (x, v, t)), VHLam _ t') -> convSkip x (inst t v) (t' v)
(VLam _ (freshCl -> (x, v, t)), t' ) -> convSkip x (inst t v) (vApp t' v)
(VHLam _ t, VLam _ (freshCl -> (x, v, t'))) -> convSkip x (t v) (inst t' v)
(VHLam _ t, VHLam _ t' ) -> let (x, v) = fresh "x" in convSkip x (t v) (t' v)
(VHLam _ t, t' ) -> let (x, v) = fresh "x" in convSkip x (t v) (vApp t' v)
(t, VLam _ (freshCl -> (x, v, t'))) -> convSkip x (vApp t v) (inst t' v)
(t, VHLam _ t' ) -> let (x, v) = fresh "x" in convSkip x (vApp t v) (t' v)
(VApp t u, VApp t' u') -> convE t t' && convE u u'
(VPi a b, VPi a' (freshCl -> (x, v, b'))) ->
convE a a' && convSkip x (inst b v) (inst b' v)
(VPi a b, VHPi (fresh -> (x, v)) a' b') ->
convE a a' && convSkip x (inst b v) (b' v)
(VHPi _ a b, VPi a' (freshCl -> (x, v, b'))) ->
convE a a' && convSkip x (b v) (inst b' v)
(VHPi _ a b, VHPi (fresh -> (x, v)) a' b') ->
convE a a' && convSkip x (b v) (b' v)
(VBool , VBool ) -> True
(VBoolLit b , VBoolLit b' ) -> b == b'
(VBoolAnd t u, VBoolAnd t' u' ) -> convE t t' && convE u u'
(VBoolOr t u, VBoolOr t' u' ) -> convE t t' && convE u u'
(VBoolEQ t u, VBoolEQ t' u' ) -> convE t t' && convE u u'
(VBoolNE t u, VBoolNE t' u' ) -> convE t t' && convE u u'
(VBoolIf t u v, VBoolIf t' u' v') -> convE t t' && convE u u' && convE v v'
(VNatural, VNatural) -> True
(VNaturalLit n, VNaturalLit n') -> n == n'
(VNaturalFold t _ u v, VNaturalFold t' _ u' v') ->
convE t t' && convE u u' && convE v v'
(VNaturalBuild t , VNaturalBuild t') -> convE t t'
(VNaturalIsZero t , VNaturalIsZero t') -> convE t t'
(VNaturalEven t , VNaturalEven t') -> convE t t'
(VNaturalOdd t , VNaturalOdd t') -> convE t t'
(VNaturalToInteger t , VNaturalToInteger t') -> convE t t'
(VNaturalShow t , VNaturalShow t') -> convE t t'
(VNaturalPlus t u , VNaturalPlus t' u') -> convE t t' && convE u u'
(VNaturalTimes t u , VNaturalTimes t' u') -> convE t t' && convE u u'
(VInteger , VInteger) -> True
(VIntegerLit t , VIntegerLit t') -> t == t'
(VIntegerShow t , VIntegerShow t') -> convE t t'
(VIntegerToDouble t , VIntegerToDouble t') -> convE t t'
(VDouble , VDouble) -> True
(VDoubleLit n , VDoubleLit n') -> Dhall.Binary.encode (DoubleLit n :: Expr Void Import) ==
Dhall.Binary.encode (DoubleLit n' :: Expr Void Import)
(VDoubleShow t , VDoubleShow t') -> convE t t'
(VText, VText) -> True
(VTextLit cs , VTextLit cs') -> convChunks cs cs'
(VTextAppend t u , VTextAppend t' u') -> convE t t' && convE u u'
(VTextShow t , VTextShow t') -> convE t t'
(VList a , VList a' ) -> convE a a'
(VListLit _ xs , VListLit _ xs') -> eqListBy convE (toList xs) (toList xs')
(VListAppend t u , VListAppend t' u' ) -> convE t t' && convE u u'
(VListBuild a t , VListBuild a' t' ) -> convE t t'
(VListLength a t , VListLength a' t' ) -> convE a a' && convE t t'
(VListHead _ t , VListHead _ t' ) -> convE t t'
(VListLast _ t , VListLast _ t' ) -> convE t t'
(VListIndexed _ t , VListIndexed _ t' ) -> convE t t'
(VListReverse _ t , VListReverse _ t' ) -> convE t t'
(VListFold a l _ t u , VListFold a' l' _ t' u' ) ->
convE a a' && convE l l' && convE t t' && convE u u'
(VOptional a , VOptional a' ) -> convE a a'
(VSome t , VSome t' ) -> convE t t'
(VNone _ , VNone _ ) -> True
(VOptionalBuild _ t , VOptionalBuild _ t' ) -> convE t t'
(VRecord m , VRecord m' ) -> eqMapsBy convE m m'
(VRecordLit m , VRecordLit m' ) -> eqMapsBy convE m m'
(VUnion m , VUnion m' ) -> eqMapsBy (eqMaybeBy convE) m m'
(VUnionLit k v m , VUnionLit k' v' m' ) -> k == k' && convE v v' &&
eqMapsBy (eqMaybeBy convE) m m'
(VCombine t u , VCombine t' u' ) -> convE t t' && convE u u'
(VCombineTypes t u , VCombineTypes t' u' ) -> convE t t' && convE u u'
(VPrefer t u , VPrefer t' u' ) -> convE t t' && convE u u'
(VMerge t u _ , VMerge t' u' _ ) -> convE t t' && convE u u'
(VField t k , VField t' k' ) -> convE t t' && k == k'
(VProject t (Left ks) , VProject t' (Left ks') ) -> convE t t' && ks == ks'
(VProject t (Right e) , VProject t' (Right e') ) -> convE t t' && convE e e'
(VInject m k mt , VInject m' k' mt' ) -> eqMapsBy (eqMaybeBy convE) m m'
&& k == k' && eqMaybeBy convE mt mt'
(VEmbed a , VEmbed a' ) -> a == a'
(VOptionalFold a t _ u v , VOptionalFold a' t' _ u' v' ) ->
convE a a' && convE t t' && convE u u' && convE v v'
(_, _) -> False
convEmpty :: Eq a => Expr s a -> Expr t a -> Bool
convEmpty (denote -> t) (denote -> u) = conv Empty (eval Empty t) (eval Empty u)
data Names
= NEmpty
| NBind !Names {-# unpack #-} !Text
deriving Show
envNames :: Env a -> Names
envNames Empty = NEmpty
envNames (Skip env x ) = NBind (envNames env) x
envNames (Extend env x _) = NBind (envNames env) x
countName' :: Text -> Names -> Int
countName' x = go 0 where
go !acc NEmpty = acc
go acc (NBind env x') = go (if x == x' then acc + 1 else acc) env
quote :: forall a. Eq a => Names -> Val a -> Expr Void a
quote !env !t =
let
fresh :: Text -> (Text, Val a)
fresh x = (x, VVar x (countName' x env))
{-# inline fresh #-}
freshCl :: Closure a -> (Text, Val a, Closure a)
freshCl cl@(Cl x _ _) = (x, snd (fresh x), cl)
{-# inline freshCl #-}
qVar :: Text -> Int -> Expr Void a
qVar !x !i = Var (V x (fromIntegral (countName' x env - i - 1)))
{-# inline qVar #-}
quoteE :: Val a -> Expr Void a
quoteE = quote env
{-# inline quoteE #-}
quoteBind :: Text -> Val a -> Expr Void a
quoteBind x = quote (NBind env x)
{-# inline quoteBind #-}
qApp :: Expr Void a -> Val a -> Expr Void a
qApp t VPrimVar = t
qApp t u = App t (quoteE u)
{-# inline qApp #-}
in case t of
VConst k -> Const k
VVar x i -> qVar x i
VApp t u -> quoteE t `qApp` u
VLam a (freshCl -> (x, v, t)) -> Lam x (quoteE a) (quoteBind x (inst t v))
VHLam i t -> case i of
Typed (fresh -> (x, v)) a -> Lam x (quoteE a) (quoteBind x (t v))
Prim -> quote env (t VPrimVar)
NaturalFoldCl{} -> quote env (t VPrimVar)
ListFoldCl{} -> quote env (t VPrimVar)
OptionalFoldCl{} -> quote env (t VPrimVar)
VPi a (freshCl -> (x, v, b)) -> Pi x (quoteE a) (quoteBind x (inst b v))
VHPi (fresh -> (x, v)) a b -> Pi x (quoteE a) (quoteBind x (b v))
VBool -> Bool
VBoolLit b -> BoolLit b
VBoolAnd t u -> BoolAnd (quoteE t) (quoteE u)
VBoolOr t u -> BoolOr (quoteE t) (quoteE u)
VBoolEQ t u -> BoolEQ (quoteE t) (quoteE u)
VBoolNE t u -> BoolNE (quoteE t) (quoteE u)
VBoolIf t u v -> BoolIf (quoteE t) (quoteE u) (quoteE v)
VNatural -> Natural
VNaturalLit n -> NaturalLit n
VNaturalFold a t u v -> NaturalFold `qApp` a `qApp` t `qApp` u `qApp` v
VNaturalBuild t -> NaturalBuild `qApp` t
VNaturalIsZero t -> NaturalIsZero `qApp` t
VNaturalEven t -> NaturalEven `qApp` t
VNaturalOdd t -> NaturalOdd `qApp` t
VNaturalToInteger t -> NaturalToInteger `qApp` t
VNaturalShow t -> NaturalShow `qApp` t
VNaturalPlus t u -> NaturalPlus (quoteE t) (quoteE u)
VNaturalTimes t u -> NaturalTimes (quoteE t) (quoteE u)
VInteger -> Integer
VIntegerLit n -> IntegerLit n
VIntegerShow t -> IntegerShow `qApp` t
VIntegerToDouble t -> IntegerToDouble `qApp` t
VDouble -> Double
VDoubleLit n -> DoubleLit n
VDoubleShow t -> DoubleShow `qApp` t
VText -> Text
VTextLit (VChunks xys z) -> TextLit (Chunks ((quoteE <$>) <$> xys) z)
VTextAppend t u -> TextAppend (quoteE t) (quoteE u)
VTextShow t -> TextShow `qApp` t
VList t -> List `qApp` t
VListLit ma ts -> ListLit (quoteE <$> ma) (quoteE <$> ts)
VListAppend t u -> ListAppend (quoteE t) (quoteE u)
VListBuild a t -> ListBuild `qApp` a `qApp` t
VListFold a l t u v -> ListFold `qApp` a `qApp` l `qApp` t `qApp` u `qApp` v
VListLength a t -> ListLength `qApp` a `qApp` t
VListHead a t -> ListHead `qApp` a `qApp` t
VListLast a t -> ListLast `qApp` a `qApp` t
VListIndexed a t -> ListIndexed `qApp` a `qApp` t
VListReverse a t -> ListReverse `qApp` a `qApp` t
VOptional a -> Optional `qApp` a
VSome t -> Some (quoteE t)
VNone t -> None `qApp` t
VOptionalFold a o t u v -> OptionalFold `qApp` a `qApp` o `qApp` t `qApp` u `qApp` v
VOptionalBuild a t -> OptionalBuild `qApp` a `qApp` t
VRecord m -> Record (quoteE <$> m)
VRecordLit m -> RecordLit (quoteE <$> m)
VUnion m -> Union ((quoteE <$>) <$> m)
VUnionLit k v m -> UnionLit k (quoteE v) ((quoteE <$>) <$> m)
VCombine t u -> Combine (quoteE t) (quoteE u)
VCombineTypes t u -> CombineTypes (quoteE t) (quoteE u)
VPrefer t u -> Prefer (quoteE t) (quoteE u)
VMerge t u ma -> Merge (quoteE t) (quoteE u) (quoteE <$> ma)
VField t k -> Field (quoteE t) k
VProject t p -> Project (quoteE t) (fmap quoteE p)
VInject m k Nothing -> Field (Union ((quoteE <$>) <$> m)) k
VInject m k (Just t) -> Field (Union ((quoteE <$>) <$> m)) k `qApp` t
VEmbed a -> Embed a
VPrimVar -> error errorMsg
nf :: Eq a => Env a -> Expr s a -> Expr t a
nf !env = coeExprVoid . quote (envNames env) . eval env . denote
nfEmpty :: Eq a => Expr s a -> Expr t a
nfEmpty = nf Empty
alphaNormalize :: Expr s a -> Expr s a
alphaNormalize = goEnv NEmpty where
goVar :: Names -> Text -> Integer -> Expr s a
goVar e topX topI = go 0 e topI where
go !acc (NBind env x) !i
| x == topX = if i == 0 then Var (V "_" acc) else go (acc + 1) env (i - 1)
| otherwise = go (acc + 1) env i
go acc NEmpty i = Var (V topX i)
goEnv :: Names -> Expr s a -> Expr s a
goEnv !e t = let
go = goEnv e
goBind x = goEnv (NBind e x)
goChunks (Chunks ts x) = Chunks ((go <$>) <$> ts) x
in case t of
Const k -> Const k
Var (V x i) -> goVar e x i
Lam x t u -> Lam "_" (go t) (goBind x u)
Pi x a b -> Pi "_" (go a) (goBind x b)
App t u -> App (go t) (go u)
Let (b :| bs) u ->
let Binding x a t = b
nil = (NBind e x, Binding "_" (goEnv e <$> a) (goEnv e t) :| [])
snoc (e, bs) (Binding x a t) =
(NBind e x, cons (Binding "_" (goEnv e <$> a) (goEnv e t)) bs)
(e', Data.List.NonEmpty.reverse -> bs') = foldl' snoc nil bs
in Let bs' (goEnv e' u)
Annot t u -> Annot (go t) (go u)
Bool -> Bool
BoolLit b -> BoolLit b
BoolAnd t u -> BoolAnd (go t) (go u)
BoolOr t u -> BoolOr (go t) (go u)
BoolEQ t u -> BoolEQ (go t) (go u)
BoolNE t u -> BoolNE (go t) (go u)
BoolIf b t f -> BoolIf (go b) (go t) (go f)
Natural -> Natural
NaturalLit n -> NaturalLit n
NaturalFold -> NaturalFold
NaturalBuild -> NaturalBuild
NaturalIsZero -> NaturalIsZero
NaturalEven -> NaturalEven
NaturalOdd -> NaturalOdd
NaturalToInteger -> NaturalToInteger
NaturalShow -> NaturalShow
NaturalPlus t u -> NaturalPlus (go t) (go u)
NaturalTimes t u -> NaturalTimes (go t) (go u)
Integer -> Integer
IntegerLit n -> IntegerLit n
IntegerShow -> IntegerShow
IntegerToDouble -> IntegerToDouble
Double -> Double
DoubleLit n -> DoubleLit n
DoubleShow -> DoubleShow
Text -> Text
TextLit cs -> TextLit (goChunks cs)
TextAppend t u -> TextAppend (go t) (go u)
TextShow -> TextShow
List -> List
ListLit ma ts -> ListLit (go <$> ma) (go <$> ts)
ListAppend t u -> ListAppend (go t) (go u)
ListBuild -> ListBuild
ListFold -> ListFold
ListLength -> ListLength
ListHead -> ListHead
ListLast -> ListLast
ListIndexed -> ListIndexed
ListReverse -> ListReverse
Optional -> Optional
OptionalLit a mt -> OptionalLit (go a) (go <$> mt)
Some t -> Some (go t)
None -> None
OptionalFold -> OptionalFold
OptionalBuild -> OptionalBuild
Record kts -> Record (go <$> kts)
RecordLit kts -> RecordLit (go <$> kts)
Union kts -> Union ((go <$>) <$> kts)
UnionLit k v kts -> UnionLit k (go v) ((go <$>) <$> kts)
Combine t u -> Combine (go t) (go u)
CombineTypes t u -> CombineTypes (go t) (go u)
Prefer t u -> Prefer (go t) (go u)
Merge x y ma -> Merge (go x) (go y) (go <$> ma)
Field t k -> Field (go t) k
Project t ks -> Project (go t) ks
Note s e -> Note s (go e)
ImportAlt t u -> ImportAlt (go t) (go u)
Embed a -> Embed a