diff --git a/benchmark/deep-nested-large-record/Main.hs b/benchmark/deep-nested-large-record/Main.hs index e2cfc3a61..7a986eafd 100644 --- a/benchmark/deep-nested-large-record/Main.hs +++ b/benchmark/deep-nested-large-record/Main.hs @@ -30,9 +30,20 @@ issue412 prelude = Criterion.whnf TypeCheck.typeOf expr $ Seq.replicate 5 $ Core.Var (Core.V "prelude" 0) `Core.Field` "types" `Core.Field` "Little" `Core.Field` "Foo" +unionPerformance :: Core.Expr s TypeCheck.X -> Criterion.Benchmarkable +unionPerformance prelude = Criterion.whnf TypeCheck.typeOf expr + where + expr = + Core.Let "x" Nothing + (Core.Let "big" Nothing (prelude `Core.Field` "types" `Core.Field` "Big") + (Core.Prefer "big" "big") + ) + "x" + main :: IO () main = do prelude <- Import.load (Core.Embed dhallPreludeImport) defaultMain [ Criterion.bench "issue 412" (issue412 prelude) + , Criterion.bench "union performance" (unionPerformance prelude) ] diff --git a/dhall.cabal b/dhall.cabal index fc2df5b86..cca0a896c 100644 --- a/dhall.cabal +++ b/dhall.cabal @@ -182,9 +182,7 @@ Library directory >= 1.2.2.0 && < 1.4 , exceptions >= 0.8.3 && < 0.11, filepath >= 1.4 && < 1.5 , - hashable < 1.3 , haskeline >= 0.7.2.1 && < 0.8 , - insert-ordered-containers >= 0.2.1.0 && < 0.3 , lens-family-core >= 1.0.0 && < 1.3 , megaparsec >= 7.0.0 && < 7.1 , memory >= 0.14 && < 0.15, @@ -221,10 +219,11 @@ Library Dhall.Hash, Dhall.Import, Dhall.Lint, - Dhall.Main + Dhall.Main, + Dhall.Map, Dhall.Parser, Dhall.Pretty, - Dhall.Repl + Dhall.Repl, Dhall.TH, Dhall.Tutorial, Dhall.TypeCheck @@ -270,8 +269,6 @@ Test-Suite tasty containers , deepseq >= 1.2.0.1 && < 1.5 , dhall , - hashable , - insert-ordered-containers == 0.2.1.0 , prettyprinter , QuickCheck >= 2.10 && < 2.13, quickcheck-instances >= 0.3.12 && < 0.4 , diff --git a/src/Dhall.hs b/src/Dhall.hs index fba15c8d4..87265159c 100644 --- a/src/Dhall.hs +++ b/src/Dhall.hs @@ -114,7 +114,6 @@ import qualified Control.Monad.Trans.State.Strict as State import qualified Data.Foldable import qualified Data.Functor.Compose import qualified Data.Functor.Product -import qualified Data.HashMap.Strict.InsOrd import qualified Data.Scientific import qualified Data.Sequence import qualified Data.Set @@ -126,6 +125,7 @@ import qualified Dhall.Binary import qualified Dhall.Context import qualified Dhall.Core import qualified Dhall.Import +import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.Pretty.Internal import qualified Dhall.TypeCheck @@ -708,10 +708,10 @@ unit :: Type () unit = Type extractOut expectedOut where extractOut (RecordLit fields) - | Data.HashMap.Strict.InsOrd.null fields = return () + | Data.Foldable.null fields = return () extractOut _ = Nothing - expectedOut = Record Data.HashMap.Strict.InsOrd.empty + expectedOut = Record mempty {-| Decode a `String` @@ -731,13 +731,13 @@ pair :: Type a -> Type b -> Type (a, b) pair l r = Type extractOut expectedOut where extractOut (RecordLit fields) = - (,) <$> ( Data.HashMap.Strict.InsOrd.lookup "_1" fields >>= extract l ) - <*> ( Data.HashMap.Strict.InsOrd.lookup "_2" fields >>= extract r ) + (,) <$> ( Dhall.Map.lookup "_1" fields >>= extract l ) + <*> ( Dhall.Map.lookup "_2" fields >>= extract r ) extractOut _ = Nothing expectedOut = Record - (Data.HashMap.Strict.InsOrd.fromList + (Dhall.Map.fromList [ ("_1", expected l) , ("_2", expected r) ] @@ -864,7 +864,7 @@ instance GenericInterpret V1 where where extract _ = Nothing - expected = Union Data.HashMap.Strict.InsOrd.empty + expected = Union mempty instance (Constructor c1, Constructor c2, GenericInterpret f1, GenericInterpret f2) => GenericInterpret (M1 C c1 f1 :+: M1 C c2 f2) where genericAutoWith options@(InterpretOptions {..}) = pure (Type {..}) @@ -885,7 +885,7 @@ instance (Constructor c1, Constructor c2, GenericInterpret f1, GenericInterpret extract _ = Nothing expected = - Union (Data.HashMap.Strict.InsOrd.fromList [(nameL, expectedL), (nameR, expectedR)]) + Union (Dhall.Map.fromList [(nameL, expectedL), (nameR, expectedR)]) Type extractL expectedL = evalState (genericAutoWith options) 1 Type extractR expectedR = evalState (genericAutoWith options) 1 @@ -904,7 +904,7 @@ instance (Constructor c, GenericInterpret (f :+: g), GenericInterpret h) => Gene extract _ = Nothing expected = - Union (Data.HashMap.Strict.InsOrd.insert name expectedR expectedL) + Union (Dhall.Map.insert name expectedR expectedL) Type extractL (Union expectedL) = evalState (genericAutoWith options) 1 Type extractR expectedR = evalState (genericAutoWith options) 1 @@ -923,7 +923,7 @@ instance (Constructor c, GenericInterpret f, GenericInterpret (g :+: h)) => Gene extract _ = Nothing expected = - Union (Data.HashMap.Strict.InsOrd.insert name expectedL expectedR) + Union (Dhall.Map.insert name expectedL expectedR) Type extractL expectedL = evalState (genericAutoWith options) 1 Type extractR (Union expectedR) = evalState (genericAutoWith options) 1 @@ -933,7 +933,7 @@ instance (GenericInterpret (f :+: g), GenericInterpret (h :+: i)) => GenericInte where extract e = fmap L1 (extractL e) <|> fmap R1 (extractR e) - expected = Union (Data.HashMap.Strict.InsOrd.union expectedL expectedR) + expected = Union (Dhall.Map.union expectedL expectedR) Type extractL (Union expectedL) = evalState (genericAutoWith options) 1 Type extractR (Union expectedR) = evalState (genericAutoWith options) 1 @@ -948,7 +948,7 @@ instance GenericInterpret U1 where where extract _ = Just U1 - expected = Record (Data.HashMap.Strict.InsOrd.fromList []) + expected = Record (Dhall.Map.fromList []) instance (GenericInterpret f, GenericInterpret g) => GenericInterpret (f :*: g) where genericAutoWith options = do @@ -959,7 +959,7 @@ instance (GenericInterpret f, GenericInterpret g) => GenericInterpret (f :*: g) pure (Type { extract = liftA2 (liftA2 (:*:)) extractL extractR - , expected = Record (Data.HashMap.Strict.InsOrd.union ktsL ktsR) + , expected = Record (Dhall.Map.union ktsL ktsR) } ) @@ -975,11 +975,11 @@ instance (Selector s, Interpret a) => GenericInterpret (M1 S s (K1 i a)) where name <- getSelName n let extract (RecordLit m) = do let name' = fieldModifier (Data.Text.pack name) - e <- Data.HashMap.Strict.InsOrd.lookup name' m + e <- Dhall.Map.lookup name' m fmap (M1 . K1) (extract' e) extract _ = Nothing let expected = - Record (Data.HashMap.Strict.InsOrd.fromList [(key, expected')]) + Record (Dhall.Map.fromList [(key, expected')]) where key = fieldModifier (Data.Text.pack name) pure (Type {..}) @@ -1117,9 +1117,9 @@ instance Inject Double where instance Inject () where injectWith _ = InputType {..} where - embed = const (RecordLit Data.HashMap.Strict.InsOrd.empty) + embed = const (RecordLit mempty) - declared = Record Data.HashMap.Strict.InsOrd.empty + declared = Record mempty instance Inject a => Inject (Maybe a) where injectWith options = InputType embedOut declaredOut @@ -1173,13 +1173,13 @@ instance (Constructor c1, Constructor c2, GenericInject f1, GenericInject f2) => genericInjectWith options@(InterpretOptions {..}) = pure (InputType {..}) where embed (L1 (M1 l)) = - UnionLit keyL (embedL l) (Data.HashMap.Strict.InsOrd.singleton keyR declaredR) + UnionLit keyL (embedL l) (Dhall.Map.singleton keyR declaredR) embed (R1 (M1 r)) = - UnionLit keyR (embedR r) (Data.HashMap.Strict.InsOrd.singleton keyL declaredL) + UnionLit keyR (embedR r) (Dhall.Map.singleton keyL declaredL) declared = - Union (Data.HashMap.Strict.InsOrd.fromList [(keyL, declaredL), (keyR, declaredR)]) + Union (Dhall.Map.fromList [(keyL, declaredL), (keyR, declaredR)]) nL :: M1 i c1 f1 a nL = undefined @@ -1197,7 +1197,7 @@ instance (Constructor c, GenericInject (f :+: g), GenericInject h) => GenericInj genericInjectWith options@(InterpretOptions {..}) = pure (InputType {..}) where embed (L1 l) = - UnionLit keyL valL (Data.HashMap.Strict.InsOrd.insert keyR declaredR ktsL') + UnionLit keyL valL (Dhall.Map.insert keyR declaredR ktsL') where UnionLit keyL valL ktsL' = embedL l embed (R1 (M1 r)) = UnionLit keyR (embedR r) ktsL @@ -1207,7 +1207,7 @@ instance (Constructor c, GenericInject (f :+: g), GenericInject h) => GenericInj keyR = constructorModifier (Data.Text.pack (conName nR)) - declared = Union (Data.HashMap.Strict.InsOrd.insert keyR declaredR ktsL) + declared = Union (Dhall.Map.insert keyR declaredR ktsL) InputType embedL (Union ktsL) = evalState (genericInjectWith options) 1 InputType embedR declaredR = evalState (genericInjectWith options) 1 @@ -1217,7 +1217,7 @@ instance (Constructor c, GenericInject f, GenericInject (g :+: h)) => GenericInj where embed (L1 (M1 l)) = UnionLit keyL (embedL l) ktsR embed (R1 r) = - UnionLit keyR valR (Data.HashMap.Strict.InsOrd.insert keyL declaredL ktsR') + UnionLit keyR valR (Dhall.Map.insert keyL declaredL ktsR') where UnionLit keyR valR ktsR' = embedR r @@ -1226,7 +1226,7 @@ instance (Constructor c, GenericInject f, GenericInject (g :+: h)) => GenericInj keyL = constructorModifier (Data.Text.pack (conName nL)) - declared = Union (Data.HashMap.Strict.InsOrd.insert keyL declaredL ktsR) + declared = Union (Dhall.Map.insert keyL declaredL ktsR) InputType embedL declaredL = evalState (genericInjectWith options) 1 InputType embedR (Union ktsR) = evalState (genericInjectWith options) 1 @@ -1235,15 +1235,15 @@ instance (GenericInject (f :+: g), GenericInject (h :+: i)) => GenericInject ((f genericInjectWith options = pure (InputType {..}) where embed (L1 l) = - UnionLit keyL valR (Data.HashMap.Strict.InsOrd.union ktsL' ktsR) + UnionLit keyL valR (Dhall.Map.union ktsL' ktsR) where UnionLit keyL valR ktsL' = embedL l embed (R1 r) = - UnionLit keyR valR (Data.HashMap.Strict.InsOrd.union ktsL ktsR') + UnionLit keyR valR (Dhall.Map.union ktsL ktsR') where UnionLit keyR valR ktsR' = embedR r - declared = Union (Data.HashMap.Strict.InsOrd.union ktsL ktsR) + declared = Union (Dhall.Map.union ktsL ktsR) InputType embedL (Union ktsL) = evalState (genericInjectWith options) 1 InputType embedR (Union ktsR) = evalState (genericInjectWith options) 1 @@ -1254,12 +1254,12 @@ instance (GenericInject f, GenericInject g) => GenericInject (f :*: g) where InputType embedInR declaredInR <- genericInjectWith options let embed (l :*: r) = - RecordLit (Data.HashMap.Strict.InsOrd.union mapL mapR) + RecordLit (Dhall.Map.union mapL mapR) where RecordLit mapL = embedInL l RecordLit mapR = embedInR r - let declared = Record (Data.HashMap.Strict.InsOrd.union mapL mapR) + let declared = Record (Dhall.Map.union mapL mapR) where Record mapL = declaredInL Record mapR = declaredInR @@ -1269,17 +1269,17 @@ instance (GenericInject f, GenericInject g) => GenericInject (f :*: g) where instance GenericInject U1 where genericInjectWith _ = pure (InputType {..}) where - embed _ = RecordLit Data.HashMap.Strict.InsOrd.empty + embed _ = RecordLit mempty - declared = Record Data.HashMap.Strict.InsOrd.empty + declared = Record mempty instance (Selector s, Inject a) => GenericInject (M1 S s (K1 i a)) where genericInjectWith opts@(InterpretOptions {..}) = do name <- fieldModifier . Data.Text.pack <$> getSelName n let embed (M1 (K1 x)) = - RecordLit (Data.HashMap.Strict.InsOrd.singleton name (embedIn x)) + RecordLit (Dhall.Map.singleton name (embedIn x)) let declared = - Record (Data.HashMap.Strict.InsOrd.singleton name declaredIn) + Record (Dhall.Map.singleton name declaredIn) pure (InputType {..}) where n :: M1 i s f a @@ -1327,7 +1327,7 @@ newtype RecordType a = RecordType ( Data.Functor.Product.Product ( Control.Applicative.Const - ( Data.HashMap.Strict.InsOrd.InsOrdHashMap + ( Dhall.Map.Map Text ( Expr Src X ) ) @@ -1360,14 +1360,14 @@ field key valueType = RecordLit fields <- return expr - Data.HashMap.Strict.InsOrd.lookup key fields + Dhall.Map.lookup key fields >>= extract valueType in RecordType ( Data.Functor.Product.Pair ( Control.Applicative.Const - ( Data.HashMap.Strict.InsOrd.singleton + ( Dhall.Map.singleton key ( Dhall.expected valueType ) ) @@ -1375,7 +1375,7 @@ field key valueType = ( Data.Functor.Compose.Compose extractBody ) ) -{-| The 'RecordInputType' divisible (contravariant) functor allows you to build +{-| The 'RecordInputType' divisible (contravariant) functor allows you to build an 'InputType' injector for a Dhall record. For example, let's take the following Haskell data type: @@ -1432,7 +1432,7 @@ field key valueType = infixr 5 >*< newtype RecordInputType a - = RecordInputType (Data.HashMap.Strict.InsOrd.InsOrdHashMap Text (InputType a)) + = RecordInputType (Dhall.Map.Map Text (InputType a)) instance Contravariant RecordInputType where contramap f (RecordInputType inputTypeRecord) = RecordInputType $ contramap f <$> inputTypeRecord @@ -1440,13 +1440,13 @@ instance Contravariant RecordInputType where instance Divisible RecordInputType where divide f (RecordInputType bInputTypeRecord) (RecordInputType cInputTypeRecord) = RecordInputType - $ Data.HashMap.Strict.InsOrd.union + $ Dhall.Map.union ((contramap $ fst . f) <$> bInputTypeRecord) ((contramap $ snd . f) <$> cInputTypeRecord) - conquer = RecordInputType Data.HashMap.Strict.InsOrd.empty + conquer = RecordInputType mempty inputFieldWith :: Text -> InputType a -> RecordInputType a -inputFieldWith name inputType = RecordInputType $ Data.HashMap.Strict.InsOrd.singleton name inputType +inputFieldWith name inputType = RecordInputType $ Dhall.Map.singleton name inputType inputField :: Inject a => Text -> RecordInputType a inputField name = inputFieldWith name inject diff --git a/src/Dhall/Binary.hs b/src/Dhall/Binary.hs index 1c7218454..f4a8da88f 100644 --- a/src/Dhall/Binary.hs +++ b/src/Dhall/Binary.hs @@ -44,11 +44,11 @@ import Options.Applicative (Parser) import Prelude hiding (exponent) import qualified Data.Foldable -import qualified Data.HashMap.Strict.InsOrd import qualified Data.Scientific import qualified Data.Sequence import qualified Data.Set import qualified Data.Text +import qualified Dhall.Map import qualified Options.Applicative -- | Supported protocol version strings @@ -277,7 +277,7 @@ encode_1_1 (Record xTs₀) = TList [ TInt 7, TMap xTs₁ ] where xTs₁ = do - (x₀, _T₀) <- Data.HashMap.Strict.InsOrd.toList xTs₀ + (x₀, _T₀) <- Dhall.Map.toList xTs₀ let x₁ = TString x₀ let _T₁ = encode_1_1 _T₀ return (x₁, _T₁) @@ -285,7 +285,7 @@ encode_1_1 (RecordLit xts₀) = TList [ TInt 8, TMap xts₁ ] where xts₁ = do - (x₀, t₀) <- Data.HashMap.Strict.InsOrd.toList xts₀ + (x₀, t₀) <- Dhall.Map.toList xts₀ let x₁ = TString x₀ let t₁ = encode_1_1 t₀ return (x₁, t₁) @@ -302,7 +302,7 @@ encode_1_1 (Union xTs₀) = TList [ TInt 11, TMap xTs₁ ] where xTs₁ = do - (x₀, _T₀) <- Data.HashMap.Strict.InsOrd.toList xTs₀ + (x₀, _T₀) <- Dhall.Map.toList xTs₀ let x₁ = TString x₀ let _T₁ = encode_1_1 _T₀ return (x₁, _T₁) @@ -312,7 +312,7 @@ encode_1_1 (UnionLit x t₀ yTs₀) = t₁ = encode_1_1 t₀ yTs₁ = do - (y₀, _T₀) <- Data.HashMap.Strict.InsOrd.toList yTs₀ + (y₀, _T₀) <- Dhall.Map.toList yTs₀ let y₁ = TString y₀ let _T₁ = encode_1_1 _T₀ return (y₁, _T₁) @@ -559,7 +559,7 @@ decode_1_1 (TList [ TInt 7, TMap xTs₁ ]) = do xTs₀ <- traverse process xTs₁ - return (Record (Data.HashMap.Strict.InsOrd.fromList xTs₀)) + return (Record (Dhall.Map.fromList xTs₀)) decode_1_1 (TList [ TInt 8, TMap xts₁ ]) = do let process (TString x, t₁) = do t₀ <- decode_1_1 t₁ @@ -570,7 +570,7 @@ decode_1_1 (TList [ TInt 8, TMap xts₁ ]) = do xts₀ <- traverse process xts₁ - return (RecordLit (Data.HashMap.Strict.InsOrd.fromList xts₀)) + return (RecordLit (Dhall.Map.fromList xts₀)) decode_1_1 (TList [ TInt 9, t₁, TString x ]) = do t₀ <- decode_1_1 t₁ @@ -594,7 +594,7 @@ decode_1_1 (TList [ TInt 11, TMap xTs₁ ]) = do xTs₀ <- traverse process xTs₁ - return (Union (Data.HashMap.Strict.InsOrd.fromList xTs₀)) + return (Union (Dhall.Map.fromList xTs₀)) decode_1_1 (TList [ TInt 12, TString x, t₁, TMap yTs₁ ]) = do t₀ <- decode_1_1 t₁ @@ -607,7 +607,7 @@ decode_1_1 (TList [ TInt 12, TString x, t₁, TMap yTs₁ ]) = do yTs₀ <- traverse process yTs₁ - return (UnionLit x t₀ (Data.HashMap.Strict.InsOrd.fromList yTs₀)) + return (UnionLit x t₀ (Dhall.Map.fromList yTs₀)) decode_1_1 (TList [ TInt 13, u₁ ]) = do u₀ <- decode_1_1 u₁ diff --git a/src/Dhall/Core.hs b/src/Dhall/Core.hs index 0628427d9..dfdb0f923 100644 --- a/src/Dhall/Core.hs +++ b/src/Dhall/Core.hs @@ -64,8 +64,6 @@ import Crypto.Hash (SHA256) import Data.Bifunctor (Bifunctor(..)) import Data.Data (Data) import Data.Foldable -import Data.Hashable (Hashable) -import Data.HashMap.Strict.InsOrd (InsOrdHashMap) import Data.HashSet (HashSet) import Data.String (IsString(..)) import Data.Scientific (Scientific) @@ -75,6 +73,7 @@ import Data.Set (Set) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Pretty) import Data.Traversable +import Dhall.Map (Map) import {-# SOURCE #-} Dhall.Pretty.Internal import GHC.Generics (Generic) import Numeric.Natural (Natural) @@ -82,14 +81,12 @@ import Prelude hiding (succ) import qualified Control.Monad import qualified Crypto.Hash -import qualified Data.List -import qualified Data.HashMap.Strict.InsOrd import qualified Data.HashSet -import qualified Data.Ord import qualified Data.Sequence import qualified Data.Set import qualified Data.Text import qualified Data.Text.Prettyprint.Doc as Pretty +import qualified Dhall.Map {-| Constants for a pure type system @@ -424,13 +421,13 @@ data Expr s a -- | > OptionalBuild ~ Optional/build | OptionalBuild -- | > Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t1 } - | Record (InsOrdHashMap Text (Expr s a)) + | Record (Map Text (Expr s a)) -- | > RecordLit [(k1, v1), (k2, v2)] ~ { k1 = v1, k2 = v2 } - | RecordLit (InsOrdHashMap Text (Expr s a)) + | RecordLit (Map Text (Expr s a)) -- | > Union [(k1, t1), (k2, t2)] ~ < k1 : t1 | k2 : t2 > - | Union (InsOrdHashMap Text (Expr s a)) + | Union (Map Text (Expr s a)) -- | > UnionLit k v [(k1, t1), (k2, t2)] ~ < k = v | k1 : t1 | k2 : t2 > - | UnionLit Text (Expr s a) (InsOrdHashMap Text (Expr s a)) + | UnionLit Text (Expr s a) (Map Text (Expr s a)) -- | > Combine x y ~ x ∧ y | Combine (Expr s a) (Expr s a) -- | > CombineTypes x y ~ x ⩓ y @@ -452,7 +449,79 @@ data Expr s a | ImportAlt (Expr s a) (Expr s a) -- | > Embed import ~ import | Embed a - deriving (Functor, Foldable, Generic, Traversable, Show, Eq, Data) + deriving (Eq, Foldable, Generic, Traversable, Show, Data) + +-- This instance is hand-written due to the fact that deriving +-- it does not give us an INLINABLE pragma. We annotate this fmap +-- implementation with this pragma below to allow GHC to, possibly, +-- inline the implementation for performance improvements. +instance Functor (Expr s) where + fmap _ (Const c) = Const c + fmap _ (Var v) = Var v + fmap f (Lam v e1 e2) = Lam v (fmap f e1) (fmap f e2) + fmap f (Pi v e1 e2) = Pi v (fmap f e1) (fmap f e2) + fmap f (App e1 e2) = App (fmap f e1) (fmap f e2) + fmap f (Let v maybeE e1 e2) = Let v (fmap (fmap f) maybeE) (fmap f e1) (fmap f e2) + fmap f (Annot e1 e2) = Annot (fmap f e1) (fmap f e2) + fmap _ Bool = Bool + fmap _ (BoolLit b) = BoolLit b + fmap f (BoolAnd e1 e2) = BoolAnd (fmap f e1) (fmap f e2) + fmap f (BoolOr e1 e2) = BoolOr (fmap f e1) (fmap f e2) + fmap f (BoolEQ e1 e2) = BoolEQ (fmap f e1) (fmap f e2) + fmap f (BoolNE e1 e2) = BoolNE (fmap f e1) (fmap f e2) + fmap f (BoolIf e1 e2 e3) = BoolIf (fmap f e1) (fmap f e2) (fmap f e3) + fmap _ Natural = Natural + fmap _ (NaturalLit n) = NaturalLit n + fmap _ NaturalFold = NaturalFold + fmap _ NaturalBuild = NaturalBuild + fmap _ NaturalIsZero = NaturalIsZero + fmap _ NaturalEven = NaturalEven + fmap _ NaturalOdd = NaturalOdd + fmap _ NaturalToInteger = NaturalToInteger + fmap _ NaturalShow = NaturalShow + fmap f (NaturalPlus e1 e2) = NaturalPlus (fmap f e1) (fmap f e2) + fmap f (NaturalTimes e1 e2) = NaturalTimes (fmap f e1) (fmap f e2) + fmap _ Integer = Integer + fmap _ (IntegerLit i) = IntegerLit i + fmap _ IntegerShow = IntegerShow + fmap _ IntegerToDouble = IntegerToDouble + fmap _ Double = Double + fmap _ (DoubleLit d) = DoubleLit d + fmap _ DoubleShow = DoubleShow + fmap _ Text = Text + fmap f (TextLit cs) = TextLit (fmap f cs) + fmap f (TextAppend e1 e2) = TextAppend (fmap f e1) (fmap f e2) + fmap _ List = List + fmap f (ListLit maybeE seqE) = ListLit (fmap (fmap f) maybeE) (fmap (fmap f) seqE) + fmap f (ListAppend e1 e2) = ListAppend (fmap f e1) (fmap f e2) + fmap _ ListBuild = ListBuild + fmap _ ListFold = ListFold + fmap _ ListLength = ListLength + fmap _ ListHead = ListHead + fmap _ ListLast = ListLast + fmap _ ListIndexed = ListIndexed + fmap _ ListReverse = ListReverse + fmap _ Optional = Optional + fmap f (OptionalLit e maybeE) = OptionalLit (fmap f e) (fmap (fmap f) maybeE) + fmap f (Some e) = Some (fmap f e) + fmap _ None = None + fmap _ OptionalFold = OptionalFold + fmap _ OptionalBuild = OptionalBuild + fmap f (Record r) = Record (fmap (fmap f) r) + fmap f (RecordLit r) = RecordLit (fmap (fmap f) r) + fmap f (Union u) = Union (fmap (fmap f) u) + fmap f (UnionLit v e u) = UnionLit v (fmap f e) (fmap (fmap f) u) + fmap f (Combine e1 e2) = Combine (fmap f e1) (fmap f e2) + fmap f (CombineTypes e1 e2) = CombineTypes (fmap f e1) (fmap f e2) + fmap f (Prefer e1 e2) = Prefer (fmap f e1) (fmap f e2) + fmap f (Merge e1 e2 maybeE) = Merge (fmap f e1) (fmap f e2) (fmap (fmap f) maybeE) + fmap f (Constructors e1) = Constructors (fmap f e1) + fmap f (Field e1 v) = Field (fmap f e1) v + fmap f (Project e1 vs) = Project (fmap f e1) vs + fmap f (Note s e1) = Note s (fmap f e1) + fmap f (ImportAlt e1 e2) = ImportAlt (fmap f e1) (fmap f e2) + fmap f (Embed a) = Embed (f a) + {-# INLINABLE fmap #-} instance Applicative (Expr s) where pure = Embed @@ -1403,12 +1472,6 @@ denote (Project a b ) = Project (denote a) b denote (ImportAlt a b ) = ImportAlt (denote a) (denote b) denote (Embed a ) = Embed a -sortMap :: (Ord k, Hashable k) => InsOrdHashMap k v -> InsOrdHashMap k v -sortMap = - Data.HashMap.Strict.InsOrd.fromList - . Data.List.sortBy (Data.Ord.comparing fst) - . Data.HashMap.Strict.InsOrd.toList - {-| Reduce an expression to its normal form, performing beta reduction and applying any custom definitions. @@ -1531,7 +1594,7 @@ normalizeWith ctx e0 = loop (denote e0) where as₁ = Data.Sequence.mapWithIndex adapt as₀ - _A₂ = Record (Data.HashMap.Strict.InsOrd.fromList kts) + _A₂ = Record (Dhall.Map.fromList kts) where kts = [ ("index", Natural) , ("value", _A₀) @@ -1541,7 +1604,7 @@ normalizeWith ctx e0 = loop (denote e0) | otherwise = Nothing adapt n a_ = - RecordLit (Data.HashMap.Strict.InsOrd.fromList kvs) + RecordLit (Dhall.Map.fromList kvs) where kvs = [ ("index", NaturalLit (fromIntegral n)) , ("value", a_) @@ -1684,48 +1747,48 @@ normalizeWith ctx e0 = loop (denote e0) None -> None OptionalFold -> OptionalFold OptionalBuild -> OptionalBuild - Record kts -> Record (sortMap kts') + Record kts -> Record (Dhall.Map.sort kts') where kts' = fmap loop kts - RecordLit kvs -> RecordLit (sortMap kvs') + RecordLit kvs -> RecordLit (Dhall.Map.sort kvs') where kvs' = fmap loop kvs - Union kts -> Union (sortMap kts') + Union kts -> Union (Dhall.Map.sort kts') where kts' = fmap loop kts - UnionLit k v kvs -> UnionLit k v' (sortMap kvs') + UnionLit k v kvs -> UnionLit k v' (Dhall.Map.sort kvs') where v' = loop v kvs' = fmap loop kvs Combine x y -> decide (loop x) (loop y) where - decide (RecordLit m) r | Data.HashMap.Strict.InsOrd.null m = + decide (RecordLit m) r | Data.Foldable.null m = r - decide l (RecordLit n) | Data.HashMap.Strict.InsOrd.null n = + decide l (RecordLit n) | Data.Foldable.null n = l decide (RecordLit m) (RecordLit n) = - RecordLit (sortMap (Data.HashMap.Strict.InsOrd.unionWith decide m n)) + RecordLit (Dhall.Map.sort (Dhall.Map.unionWith decide m n)) decide l r = Combine l r CombineTypes x y -> decide (loop x) (loop y) where - decide (Record m) r | Data.HashMap.Strict.InsOrd.null m = + decide (Record m) r | Data.Foldable.null m = r - decide l (Record n) | Data.HashMap.Strict.InsOrd.null n = + decide l (Record n) | Data.Foldable.null n = l decide (Record m) (Record n) = - Record (sortMap (Data.HashMap.Strict.InsOrd.unionWith decide m n)) + Record (Dhall.Map.sort (Dhall.Map.unionWith decide m n)) decide l r = CombineTypes l r Prefer x y -> decide (loop x) (loop y) where - decide (RecordLit m) r | Data.HashMap.Strict.InsOrd.null m = + decide (RecordLit m) r | Data.Foldable.null m = r - decide l (RecordLit n) | Data.HashMap.Strict.InsOrd.null n = + decide l (RecordLit n) | Data.Foldable.null n = l decide (RecordLit m) (RecordLit n) = - RecordLit (sortMap (Data.HashMap.Strict.InsOrd.union n m)) + RecordLit (Dhall.Map.sort (Dhall.Map.union n m)) decide l r = Prefer l r Merge x y t -> @@ -1733,7 +1796,7 @@ normalizeWith ctx e0 = loop (denote e0) RecordLit kvsX -> case y' of UnionLit kY vY _ -> - case Data.HashMap.Strict.InsOrd.lookup kY kvsX of + case Dhall.Map.lookup kY kvsX of Just vX -> loop (App vX vY) Nothing -> Merge x' y' t' _ -> Merge x' y' t' @@ -1746,18 +1809,18 @@ normalizeWith ctx e0 = loop (denote e0) case t' of Union kts -> RecordLit kvs where - kvs = Data.HashMap.Strict.InsOrd.mapWithKey adapt kts + kvs = Dhall.Map.mapWithKey adapt kts adapt k t_ = Lam k t_ (UnionLit k (Var (V k 0)) rest) where - rest = Data.HashMap.Strict.InsOrd.delete k kts + rest = Dhall.Map.delete k kts _ -> Constructors t' where t' = loop t Field r x -> case loop r of RecordLit kvs -> - case Data.HashMap.Strict.InsOrd.lookup x kvs of + case Dhall.Map.lookup x kvs of Just v -> loop v Nothing -> Field (RecordLit (fmap loop kvs)) x r' -> Field r' x @@ -1768,12 +1831,12 @@ normalizeWith ctx e0 = loop (denote e0) Just s -> loop (RecordLit kvs') where - kvs' = Data.HashMap.Strict.InsOrd.fromList s + kvs' = Dhall.Map.fromList s Nothing -> Project (RecordLit (fmap loop kvs)) xs where adapt x = do - v <- Data.HashMap.Strict.InsOrd.lookup x kvs + v <- Dhall.Map.lookup x kvs return (x, v) r' -> Project r' xs Note _ e' -> loop e' @@ -1948,26 +2011,26 @@ isNormalized e0 = loop (denote e0) None -> True OptionalFold -> True OptionalBuild -> True - Record kts -> all loop kts - RecordLit kvs -> all loop kvs - Union kts -> all loop kts - UnionLit _ v kvs -> loop v && all loop kvs + Record kts -> Dhall.Map.isSorted kts && all loop kts + RecordLit kvs -> Dhall.Map.isSorted kvs && all loop kvs + Union kts -> Dhall.Map.isSorted kts && all loop kts + UnionLit _ v kvs -> loop v && Dhall.Map.isSorted kvs && all loop kvs Combine x y -> loop x && loop y && decide x y where - decide (RecordLit m) _ | Data.HashMap.Strict.InsOrd.null m = False - decide _ (RecordLit n) | Data.HashMap.Strict.InsOrd.null n = False + decide (RecordLit m) _ | Data.Foldable.null m = False + decide _ (RecordLit n) | Data.Foldable.null n = False decide (RecordLit _) (RecordLit _) = False decide _ _ = True CombineTypes x y -> loop x && loop y && decide x y where - decide (Record m) _ | Data.HashMap.Strict.InsOrd.null m = False - decide _ (Record n) | Data.HashMap.Strict.InsOrd.null n = False + decide (Record m) _ | Data.Foldable.null m = False + decide _ (Record n) | Data.Foldable.null n = False decide (Record _) (Record _) = False decide _ _ = True Prefer x y -> loop x && loop y && decide x y where - decide (RecordLit m) _ | Data.HashMap.Strict.InsOrd.null m = False - decide _ (RecordLit n) | Data.HashMap.Strict.InsOrd.null n = False + decide (RecordLit m) _ | Data.Foldable.null m = False + decide _ (RecordLit n) | Data.Foldable.null n = False decide (RecordLit _) (RecordLit _) = False decide _ _ = True Merge x y t -> loop x && loop y && all loop t && @@ -1975,7 +2038,7 @@ isNormalized e0 = loop (denote e0) RecordLit kvsX -> case y of UnionLit kY _ _ -> - case Data.HashMap.Strict.InsOrd.lookup kY kvsX of + case Dhall.Map.lookup kY kvsX of Just _ -> False Nothing -> True _ -> True @@ -1988,14 +2051,14 @@ isNormalized e0 = loop (denote e0) Field r x -> loop r && case r of RecordLit kvs -> - case Data.HashMap.Strict.InsOrd.lookup x kvs of + case Dhall.Map.lookup x kvs of Just _ -> False Nothing -> True _ -> True Project r xs -> loop r && case r of RecordLit kvs -> - if all (flip Data.HashMap.Strict.InsOrd.member kvs) xs + if all (flip Dhall.Map.member kvs) xs then False else True _ -> True diff --git a/src/Dhall/Diff.hs b/src/Dhall/Diff.hs index a08f32457..331eb3f03 100644 --- a/src/Dhall/Diff.hs +++ b/src/Dhall/Diff.hs @@ -17,7 +17,6 @@ module Dhall.Diff ( import Data.Foldable (fold, toList) import Data.Function (on) -import Data.HashMap.Strict.InsOrd (InsOrdHashMap) import Data.List.NonEmpty (NonEmpty(..)) import Data.Monoid (Any(..)) import Data.Scientific (Scientific) @@ -28,16 +27,17 @@ import Data.String (IsString(..)) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty) import Dhall.Core (Chunks (..), Const(..), Expr(..), Var(..)) +import Dhall.Map (Map) import Dhall.Pretty.Internal (Ann) import Numeric.Natural (Natural) import qualified Data.Algorithm.Diff as Algo.Diff -import qualified Data.HashMap.Strict.InsOrd as HashMap import qualified Data.List.NonEmpty import qualified Data.Set import qualified Data.Text import qualified Data.Text.Prettyprint.Doc as Pretty import qualified Dhall.Core +import qualified Dhall.Map import qualified Dhall.Pretty.Internal as Internal data Diff = @@ -248,14 +248,14 @@ enclosed' l m docs = diffKeyVals :: (Eq a, Pretty a) => Diff - -> InsOrdHashMap Text (Expr s a) - -> InsOrdHashMap Text (Expr s a) + -> Map Text (Expr s a) + -> Map Text (Expr s a) -> [Diff] diffKeyVals assign kvsL kvsR = diffFieldNames <> diffFieldValues <> (if anyEqual then [ ignore ] else []) where - ksL = Data.Set.fromList (HashMap.keys kvsL) - ksR = Data.Set.fromList (HashMap.keys kvsR) + ksL = Data.Set.fromList (Dhall.Map.keys kvsL) + ksR = Data.Set.fromList (Dhall.Map.keys kvsR) extraL = Data.Set.difference ksL ksR extraR = Data.Set.difference ksR ksL @@ -270,10 +270,10 @@ diffKeyVals assign kvsL kvsR = <> ignore ] - shared = HashMap.intersectionWith diffExpression kvsL kvsR + shared = Dhall.Map.intersectionWith diffExpression kvsL kvsR diffFieldValues = - filter (not . same) (HashMap.foldMapWithKey adapt shared) + filter (not . same) (Dhall.Map.foldMapWithKey adapt shared) where adapt key doc = [ (if ksL == ksR then mempty else " ") @@ -391,17 +391,17 @@ isBoth p diffRecord :: (Eq a, Pretty a) - => InsOrdHashMap Text (Expr s a) -> InsOrdHashMap Text (Expr s a) -> Diff + => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff diffRecord kvsL kvsR = braced (diffKeyVals colon kvsL kvsR) diffRecordLit :: (Eq a, Pretty a) - => InsOrdHashMap Text (Expr s a) -> InsOrdHashMap Text (Expr s a) -> Diff + => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff diffRecordLit kvsL kvsR = braced (diffKeyVals equals kvsL kvsR) diffUnion :: (Eq a, Pretty a) - => InsOrdHashMap Text (Expr s a) -> InsOrdHashMap Text (Expr s a) -> Diff + => Map Text (Expr s a) -> Map Text (Expr s a) -> Diff diffUnion kvsL kvsR = angled (diffKeyVals colon kvsL kvsR) diffUnionLit @@ -410,8 +410,8 @@ diffUnionLit -> Text -> Expr s a -> Expr s a - -> InsOrdHashMap Text (Expr s a) - -> InsOrdHashMap Text (Expr s a) + -> Map Text (Expr s a) + -> Map Text (Expr s a) -> Diff diffUnionLit kL kR vL vR kvsL kvsR = langle diff --git a/src/Dhall/Freeze.hs b/src/Dhall/Freeze.hs index 3b73d5df4..50b7f92e7 100644 --- a/src/Dhall/Freeze.hs +++ b/src/Dhall/Freeze.hs @@ -13,7 +13,7 @@ import Data.Maybe (fromMaybe) import Data.Text import Dhall.Binary (ProtocolVersion(..)) import Dhall.Core (Expr(..), Import(..), ImportHashed(..)) -import Dhall.Import (hashExpression, protocolVersion) +import Dhall.Import (protocolVersion) import Dhall.Parser (exprAndHeaderFromText, Src) import Dhall.Pretty (annToAnsiStyle, layoutOpts) import Lens.Family (set) diff --git a/src/Dhall/Import.hs b/src/Dhall/Import.hs index 8419a0a53..4afc8c4f5 100644 --- a/src/Dhall/Import.hs +++ b/src/Dhall/Import.hs @@ -177,7 +177,6 @@ import qualified Data.ByteString import qualified Data.ByteString.Lazy import qualified Data.CaseInsensitive import qualified Data.Foldable -import qualified Data.HashMap.Strict.InsOrd import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map.Strict as Map import qualified Data.Text.Encoding @@ -185,6 +184,7 @@ import qualified Data.Text as Text import qualified Data.Text.IO import qualified Dhall.Binary import qualified Dhall.Core +import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.Pretty.Internal import qualified Dhall.TypeCheck @@ -409,8 +409,8 @@ toHeader :: Expr s a -> Maybe (CI Data.ByteString.ByteString, Data.ByteString.ByteString) toHeader (RecordLit m) = do - TextLit (Chunks [] keyText ) <- Data.HashMap.Strict.InsOrd.lookup "header" m - TextLit (Chunks [] valueText) <- Data.HashMap.Strict.InsOrd.lookup "value" m + TextLit (Chunks [] keyText ) <- Dhall.Map.lookup "header" m + TextLit (Chunks [] valueText) <- Dhall.Map.lookup "value" m let keyBytes = Data.Text.Encoding.encodeUtf8 keyText let valueBytes = Data.Text.Encoding.encodeUtf8 valueText return (Data.CaseInsensitive.mk keyBytes, valueBytes) @@ -631,7 +631,7 @@ exprFromUncachedImport (Import {..}) = do expected = App List ( Record - ( Data.HashMap.Strict.InsOrd.fromList + ( Dhall.Map.fromList [("header", Text), ("value", Text)] ) ) diff --git a/src/Dhall/Map.hs b/src/Dhall/Map.hs new file mode 100644 index 000000000..8da87feeb --- /dev/null +++ b/src/Dhall/Map.hs @@ -0,0 +1,481 @@ +{-# LANGUAGE CPP #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE RecordWildCards #-} + +-- | `Map` type used to represent records and unions + +module Dhall.Map + ( -- * Type + Map + + -- * Construction + , singleton + , fromList + + -- * Sorting + , sort + , isSorted + + -- * Insertion + , insert + , insertWith + + -- * Deletion/Update + , delete + , filter + , mapMaybe + + -- * Query + , lookup + , member + , uncons + + -- * Combine + , union + , unionWith + , intersection + , intersectionWith + , difference + + -- * Traversals + , mapWithKey + , traverseWithKey + , traverseWithKey_ + , foldMapWithKey + + -- * Conversions + , toList + , toMap + , keys + ) where + +import Control.Applicative ((<|>)) +import Data.Data (Data) +import Data.Semigroup +import Prelude hiding (filter, lookup) + +import qualified Data.Functor +import qualified Data.Map +import qualified Data.Set +import qualified Prelude + +{-| A `Map` that remembers the original ordering of keys + + This is primarily used so that formatting preserves field order + + This is done primarily to avoid a dependency on @insert-ordered-containers@ + and also to improve performance +-} +data Map k v = Map (Data.Map.Map k v) [k] + deriving (Data) + +instance (Eq k, Eq v) => Eq (Map k v) where + (Map m1 ks) == (Map m2 ks') = m1 == m2 && ks == ks' + {-# INLINABLE (==) #-} + +instance Functor (Map k) where + fmap f (Map m ks) = Map (fmap f m) ks + {-# INLINABLE fmap #-} + +instance Foldable (Map k) where + foldr f z (Map m _) = foldr f z m + {-# INLINABLE foldr #-} + + foldMap f (Map m _) = foldMap f m + {-# INLINABLE foldMap #-} + +instance Traversable (Map k) where + traverse f (Map m ks) = (\m' -> Map m' ks) <$> traverse f m + {-# INLINABLE traverse #-} + +instance Ord k => Data.Semigroup.Semigroup (Map k v) where + (<>) = union + {-# INLINABLE (<>) #-} + +instance Ord k => Monoid (Map k v) where + mempty = Map Data.Map.empty [] + {-# INLINABLE mempty #-} + +#if !(MIN_VERSION_base(4,11,0)) + mappend = (<>) + {-# INLINABLE mappend #-} +#endif + +instance (Show k, Show v, Ord k) => Show (Map k v) where + showsPrec d m = + showParen (d > 10) (showString "Dhall.Map.fromList " . showsPrec 11 kvs) + where + kvs = toList m + +{-| Create a `Map` from a single key-value pair + +>>> singleton "A" 1 +Dhall.Map.fromList [("A",1)] +-} +singleton :: k -> v -> Map k v +singleton k v = Map m ks + where + m = Data.Map.singleton k v + + ks = pure k +{-# INLINABLE singleton #-} + +{-| Create a `Map` from a list of key-value pairs + +> fromList empty = mempty +> +> fromList (x <|> y) = fromList x <> fromList y + +>>> fromList [("B",1),("A",2)] -- The map preserves order +Dhall.Map.fromList [("B",1),("A",2)] +>>> fromList [("A",1),("A",2)] -- For duplicates, later values take precedence +Dhall.Map.fromList [("A",2)] +-} +fromList :: Ord k => [(k, v)] -> Map k v +fromList kvs = Map m ks + where + m = Data.Map.fromList kvs + + ks = nubOrd (map fst kvs) +{-# INLINABLE fromList #-} + +{-| Remove duplicates from a list + +>>> nubOrd [1,2,3] +[1,2,3] +>>> nubOrd [1,1,3] +[1,3] +-} +nubOrd :: Ord k => [k] -> [k] +nubOrd = go Data.Set.empty + where + go _ [] = [] + go set (k:ks) + | Data.Set.member k set = go set ks + | otherwise = k : go (Data.Set.insert k set) ks +{-# INLINABLE nubOrd #-} + +{-| Sort the keys of a `Map`, forgetting the original ordering + +> sort (sort x) = sort x + +>>> sort (fromList [("B",1),("A",2)]) +Dhall.Map.fromList [("A",2),("B",1)] +-} +sort :: Ord k => Map k v -> Map k v +sort (Map m _) = Map m ks + where + ks = Data.Map.keys m +{-# INLINABLE sort #-} + +{-| Check if the keys of a `Map` are already sorted + +> isSorted (sort m) = True + +>>> isSorted (fromList [("B",1),("A",2)]) -- Sortedness is based only on keys +False +>>> isSorted (fromList [("A",2),("B",1)]) +True +-} +isSorted :: Eq k => Map k v -> Bool +isSorted (Map m k) = Data.Map.keys m == k +{-# INLINABLE isSorted #-} + +{-| Insert a key-value pair into a `Map`, overriding any previous value stored + underneath the same key, if present + +> insert = insertWith (\v _ -> v) + +>>> insert "C" 1 (fromList [("B",2),("A",3)]) -- Values are inserted on left +Dhall.Map.fromList [("C",1),("B",2),("A",3)] +>>> insert "C" 1 (fromList [("C",2),("A",3)]) -- New value takes precedence +Dhall.Map.fromList [("C",1),("A",3)] +-} +insert :: Ord k => k -> v -> Map k v -> Map k v +insert k v (Map m ks) = Map m' ks' + where + m' = Data.Map.insert k v m + + ks' | elem k ks = ks + | otherwise = k : ks +{-# INLINABLE insert #-} + +{-| Insert a key-value pair into a `Map`, using the supplied function to combine + the new value with any old value underneath the same key, if present + +>>> insertWith (+) "C" 1 (fromList [("B",2),("A",3)]) -- No collision +Dhall.Map.fromList [("C",1),("B",2),("A",3)] +>>> insertWith (+) "C" 1 (fromList [("C",2),("A",3)]) -- Collision +Dhall.Map.fromList [("C",3),("A",3)] +-} +insertWith :: Ord k => (v -> v -> v) -> k -> v -> Map k v -> Map k v +insertWith f k v (Map m ks) = Map m' ks' + where + m' = Data.Map.insertWith f k v m + + ks' | elem k ks = ks + | otherwise = k : ks +{-# INLINABLE insertWith #-} + +{-| Delete a key from a `Map` if present, otherwise return the original `Map` + +>>> delete "B" (fromList [("C",1),("B",2),("A",3)]) +Dhall.Map.fromList [("C",1),("A",3)] +>>> delete "D" (fromList [("C",1),("B",2),("A",3)]) +Dhall.Map.fromList [("C",1),("B",2),("A",3)] +-} +delete :: Ord k => k -> Map k v -> Map k v +delete k (Map m ks) = Map m' ks' + where + m' = Data.Map.delete k m + + ks' = Prelude.filter (k /=) ks +{-# INLINABLE delete #-} + +{-| Keep all values that satisfy the given predicate + +>>> filter even (fromList [("C",3),("B",2),("A",1)]) +Dhall.Map.fromList [("B",2)] +>>> filter odd (fromList [("C",3),("B",2),("A",1)]) +Dhall.Map.fromList [("C",3),("A",1)] +-} +filter :: Ord k => (a -> Bool) -> Map k a -> Map k a +filter predicate (Map m ks) = Map m' ks' + where + m' = Data.Map.filter predicate m + + set = Data.Map.keysSet m' + + ks' = Prelude.filter (\k -> Data.Set.member k set) ks +{-# INLINABLE filter #-} + +{-| Transform all values in a `Map` using the supplied function, deleting the + key if the function returns `Nothing` + +>>> mapMaybe Data.Maybe.listToMaybe (fromList [("C",[1]),("B",[]),("A",[3])]) +Dhall.Map.fromList [("C",1),("A",3)] +-} +mapMaybe :: Ord k => (a -> Maybe b) -> Map k a -> Map k b +mapMaybe f (Map m ks) = Map m' ks' + where + m' = Data.Map.mapMaybe f m + + set = Data.Map.keysSet m' + + ks' = Prelude.filter (\k -> Data.Set.member k set) ks +{-# INLINABLE mapMaybe #-} + +{-| Retrieve a key from a `Map` + +> lookup k mempty = empty +> +> lookup k (x <> y) = lookup k y <|> lookup k x + +>>> lookup "A" (fromList [("B",1),("A",2)]) +Just 2 +>>> lookup "C" (fromList [("B",1),("A",2)]) +Nothing +-} +lookup :: Ord k => k -> Map k v -> Maybe v +lookup k (Map m _) = Data.Map.lookup k m +{-# INLINABLE lookup #-} + +{-| Retrieve the first key, value of the 'Map', if present, + and also returning the rest of the 'Map'. + +> uncons mempty = empty +> +> uncons (singleton k v) = (k, v, mempty) + +>>> uncons (fromList [("C",1),("B",2),("A",3)]) +Just ("C",1,Dhall.Map.fromList [("B",2),("A",3)]) +>>> uncons (fromList []) +Nothing +-} +uncons :: Ord k => Map k v -> Maybe (k, v, Map k v) +uncons (Map _ []) = Nothing +uncons (Map m (k:ks)) = Just (k, m Data.Map.! k, Map (Data.Map.delete k m) ks) +{-# INLINABLE uncons #-} + +{-| Check if a key belongs to a `Map` + +> member k mempty = False +> +> member k (x <> y) = member k x || member k y + +>>> member "A" (fromList [("B",1),("A",2)]) +True +>>> member "C" (fromList [("B",1),("A",2)]) +False +-} +member :: Ord k => k -> Map k v -> Bool +member k (Map m _) = Data.Map.member k m +{-# INLINABLE member #-} + +{-| Combine two `Map`s, preferring keys from the first `Map` + +> union = unionWith (\v _ -> v) + +>>> union (fromList [("D",1),("C",2)]) (fromList [("B",3),("A",4)]) +Dhall.Map.fromList [("D",1),("C",2),("B",3),("A",4)] +>>> union (fromList [("D",1),("C",2)]) (fromList [("C",3),("A",4)]) +Dhall.Map.fromList [("D",1),("C",2),("A",4)] +-} +union :: Ord k => Map k v -> Map k v -> Map k v +union (Map mL ksL) (Map mR ksR) = Map m ks + where + m = Data.Map.union mL mR + + setL = Data.Map.keysSet mL + + ks = ksL <|> Prelude.filter (\k -> Data.Set.notMember k setL) ksR +{-# INLINABLE union #-} + +{-| Combine two `Map`s using a combining function for colliding keys + +>>> unionWith (+) (fromList [("D",1),("C",2)]) (fromList [("B",3),("A",4)]) +Dhall.Map.fromList [("D",1),("C",2),("B",3),("A",4)] +>>> unionWith (+) (fromList [("D",1),("C",2)]) (fromList [("C",3),("A",4)]) +Dhall.Map.fromList [("D",1),("C",5),("A",4)] +-} +unionWith :: Ord k => (v -> v -> v) -> Map k v -> Map k v -> Map k v +unionWith combine (Map mL ksL) (Map mR ksR) = Map m ks + where + m = Data.Map.unionWith combine mL mR + + setL = Data.Map.keysSet mL + + ks = ksL <|> Prelude.filter (\k -> Data.Set.notMember k setL) ksR +{-# INLINABLE unionWith #-} + +{-| Combine two `Map` on their shared keys, keeping the value from the first + `Map` + +> intersection = intersectionWith (\v _ -> v) + +>>> intersection (fromList [("C",1),("B",2)]) (fromList [("B",3),("A",4)]) +Dhall.Map.fromList [("B",2)] +-} +intersection :: Ord k => Map k a -> Map k b -> Map k a +intersection (Map mL ksL) (Map mR _) = Map m ks + where + m = Data.Map.intersection mL mR + + setL = Data.Map.keysSet mL + setR = Data.Map.keysSet mR + set = Data.Set.intersection setL setR + ks = Prelude.filter (\k -> Data.Set.member k set) ksL +{-# INLINABLE intersection #-} + +{-| Combine two `Map`s on their shared keys, using the supplied function to + combine values from the first and second `Map` + +>>> intersectionWith (+) (fromList [("C",1),("B",2)]) (fromList [("B",3),("A",4)]) +Dhall.Map.fromList [("B",5)] +-} +intersectionWith :: Ord k => (a -> b -> c) -> Map k a -> Map k b -> Map k c +intersectionWith combine (Map mL ksL) (Map mR _) = Map m ks + where + m = Data.Map.intersectionWith combine mL mR + + setL = Data.Map.keysSet mL + setR = Data.Map.keysSet mR + set = Data.Set.intersection setL setR + ks = Prelude.filter (\k -> Data.Set.member k set) ksL +{-# INLINABLE intersectionWith #-} + +{-| Compute the difference of two `Map`s by subtracting all keys from the + second `Map` from the first `Map` + +>>> difference (fromList [("C",1),("B",2)]) (fromList [("B",3),("A",4)]) +Dhall.Map.fromList [("C",1)] +-} +difference :: Ord k => Map k a -> Map k b -> Map k a +difference (Map mL ksL) (Map mR _) = Map m ks + where + m = Data.Map.difference mL mR + + setR = Data.Map.keysSet mR + + ks = Prelude.filter (\k -> Data.Set.notMember k setR) ksL +{-# INLINABLE difference #-} + +{-| Fold all of the key-value pairs in a `Map`, in their original order + +>>> foldMapWithKey (,) (fromList [("B",[1]),("A",[2])]) +("BA",[1,2]) +-} +foldMapWithKey :: (Monoid m, Ord k) => (k -> a -> m) -> Map k a -> m +foldMapWithKey f m = foldMap (uncurry f) (toList m) +{-# INLINABLE foldMapWithKey #-} + +{-| Transform the values of a `Map` using their corresponding key + +> mapWithKey (pure id) = id +> +> mapWithKey (liftA2 (.) f g) = mapWithKey f . mapWithKey g + +> mapWithKey f mempty = mempty +> +> mapWithKey f (x <> y) = mapWithKey f x <> mapWithKey f y + +>>> mapWithKey (,) (fromList [("B",1),("A",2)]) +Dhall.Map.fromList [("B",("B",1)),("A",("A",2))] +-} +mapWithKey :: (k -> a -> b) -> Map k a -> Map k b +mapWithKey f (Map m ks) = Map m' ks + where + m' = Data.Map.mapWithKey f m +{-# INLINABLE mapWithKey #-} + +{-| Traverse all of the key-value pairs in a `Map`, in their original order + +>>> traverseWithKey (,) (fromList [("B",1),("A",2)]) +("BA",Dhall.Map.fromList [("B",1),("A",2)]) +-} +traverseWithKey + :: Ord k => Applicative f => (k -> a -> f b) -> Map k a -> f (Map k b) +traverseWithKey f m = fmap fromList (traverse f' (toList m)) + where + f' (k, a) = fmap ((,) k) (f k a) +{-# INLINABLE traverseWithKey #-} + +{-| Traverse all of the key-value pairs in a `Map`, in their original order + where the result of the computation can be forgotten. + +>>> traverseWithKey_ (\k v -> print (k, v)) (fromList [("B",1),("A",2)]) +("B",1) +("A",2) +-} +traverseWithKey_ + :: Ord k => Applicative f => (k -> a -> f ()) -> Map k a -> f () +traverseWithKey_ f m = Data.Functor.void (traverseWithKey f m) +{-# INLINABLE traverseWithKey_ #-} + +{-| Convert a `Map` to a list of key-value pairs in the original order of keys + +>>> toList (fromList [("B",1),("A",2)]) +[("B",1),("A",2)] +-} +toList :: Ord k => Map k v -> [(k, v)] +toList (Map m ks) = fmap (\k -> (k, m Data.Map.! k)) ks +{-# INLINABLE toList #-} + +{-| Convert a @"Dhall.Map".`Map`@ to a @"Data.Map".`Data.Map.Map`@ + +>>> toMap (fromList [("B",1),("A",2)]) -- Order is lost upon conversion +fromList [("A",2),("B",1)] +-} +toMap :: Map k v -> Data.Map.Map k v +toMap (Map m _) = m +{-# INLINABLE toMap #-} + +{-| Return the keys from a `Map` in their original order + +>>> keys (fromList [("B",1),("A",2)]) +["B","A"] +-} +keys :: Map k v -> [k] +keys (Map _ ks) = ks +{-# INLINABLE keys #-} diff --git a/src/Dhall/Parser/Combinators.hs b/src/Dhall/Parser/Combinators.hs index bd2616adc..5be58a3fc 100644 --- a/src/Dhall/Parser/Combinators.hs +++ b/src/Dhall/Parser/Combinators.hs @@ -8,7 +8,6 @@ module Dhall.Parser.Combinators where import Control.Applicative (Alternative (..), liftA2) import Control.Monad (MonadPlus (..)) import Data.Data (Data) -import Data.HashMap.Strict.InsOrd (InsOrdHashMap) import Data.Semigroup (Semigroup (..)) import Data.Sequence (ViewL (..)) import Data.Set (Set) @@ -16,18 +15,18 @@ import Data.String (IsString (..)) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Pretty (..)) import Data.Void (Void) +import Dhall.Map (Map) import Prelude hiding (const, pi) import Text.Parser.Combinators (try, ()) import Text.Parser.Token (TokenParsing (..)) +import qualified Control.Monad.Fail import qualified Data.Char -import qualified Data.HashMap.Strict.InsOrd -import qualified Data.List import qualified Data.Sequence import qualified Data.Set import qualified Data.Text +import qualified Dhall.Map import qualified Dhall.Util -import qualified Control.Monad.Fail import qualified Text.Megaparsec import qualified Text.Megaparsec.Char import qualified Text.Parser.Char @@ -246,7 +245,7 @@ noDuplicates = go Data.Set.empty then fail "Duplicate key" else go (Data.Set.insert x found) xs -toMap :: [(Text, a)] -> Parser (InsOrdHashMap Text a) +toMap :: [(Text, a)] -> Parser (Map Text a) toMap kvs = do let adapt (k, v) = (k, pure v) let m = fromListWith (<|>) (fmap adapt kvs) @@ -258,10 +257,8 @@ toMap kvs = do else Text.Parser.Combinators.unexpected ("duplicate field: " ++ Data.Text.unpack k) - Data.HashMap.Strict.InsOrd.traverseWithKey action m + Dhall.Map.traverseWithKey action m where - fromListWith combine = Data.List.foldl' snoc nil + fromListWith combine = foldr cons mempty where - nil = Data.HashMap.Strict.InsOrd.empty - - snoc m (k, v) = Data.HashMap.Strict.InsOrd.insertWith combine k v m + cons (k, v) = Dhall.Map.insertWith combine k v diff --git a/src/Dhall/Parser/Expression.hs b/src/Dhall/Parser/Expression.hs index 0f61d0b22..351ccdc4c 100644 --- a/src/Dhall/Parser/Expression.hs +++ b/src/Dhall/Parser/Expression.hs @@ -20,7 +20,6 @@ import qualified Crypto.Hash import qualified Data.ByteArray.Encoding import qualified Data.ByteString import qualified Data.Char -import qualified Data.HashMap.Strict.InsOrd import qualified Data.Sequence import qualified Data.Text import qualified Data.Text.Encoding @@ -502,11 +501,11 @@ completeExpression embedded = completeExpression_ where alternative0 = do _equal - return (RecordLit Data.HashMap.Strict.InsOrd.empty) + return (RecordLit mempty) alternative1 = nonEmptyRecordTypeOrLiteral - alternative2 = return (Record Data.HashMap.Strict.InsOrd.empty) + alternative2 = return (Record mempty) nonEmptyRecordTypeOrLiteral = do a <- label @@ -539,7 +538,7 @@ completeExpression embedded = completeExpression_ unionTypeOrLiteral = nonEmptyUnionTypeOrLiteral - <|> return (Union Data.HashMap.Strict.InsOrd.empty) + <|> return (Union mempty) nonEmptyUnionTypeOrLiteral = do (f, kvs) <- loop diff --git a/src/Dhall/Pretty/Internal.hs b/src/Dhall/Pretty/Internal.hs index e31d8bc35..ce7a61e51 100644 --- a/src/Dhall/Pretty/Internal.hs +++ b/src/Dhall/Pretty/Internal.hs @@ -60,18 +60,17 @@ import {-# SOURCE #-} Dhall.Core import Control.Applicative (Applicative(..), (<$>)) #endif import Data.Foldable -import Data.HashMap.Strict.InsOrd (InsOrdHashMap) import Data.Monoid ((<>)) import Data.Scientific (Scientific) import Data.Set (Set) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty, space) +import Dhall.Map (Map) import Numeric.Natural (Natural) import Prelude hiding (succ) import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Terminal import qualified Data.Char -import qualified Data.HashMap.Strict.InsOrd import qualified Data.HashSet import qualified Data.List import qualified Data.Set @@ -79,6 +78,7 @@ import qualified Data.Text as Text import qualified Data.Text.Prettyprint.Doc as Pretty import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty +import qualified Dhall.Map {-| Annotation type used to tag elements in a pretty-printed document for syntax highlighting purposes @@ -818,25 +818,25 @@ prettyCharacterSet characterSet = prettyExpression where long = Pretty.hardline <> " " <> prettyExpression value - prettyRecord :: Pretty a => InsOrdHashMap Text (Expr s a) -> Doc Ann + prettyRecord :: Pretty a => Map Text (Expr s a) -> Doc Ann prettyRecord = - braces . map (prettyKeyValue colon) . Data.HashMap.Strict.InsOrd.toList + braces . map (prettyKeyValue colon) . Dhall.Map.toList - prettyRecordLit :: Pretty a => InsOrdHashMap Text (Expr s a) -> Doc Ann + prettyRecordLit :: Pretty a => Map Text (Expr s a) -> Doc Ann prettyRecordLit a - | Data.HashMap.Strict.InsOrd.null a = + | Data.Foldable.null a = lbrace <> equals <> rbrace | otherwise - = braces (map (prettyKeyValue equals) (Data.HashMap.Strict.InsOrd.toList a)) + = braces (map (prettyKeyValue equals) (Dhall.Map.toList a)) - prettyUnion :: Pretty a => InsOrdHashMap Text (Expr s a) -> Doc Ann + prettyUnion :: Pretty a => Map Text (Expr s a) -> Doc Ann prettyUnion = - angles . map (prettyKeyValue colon) . Data.HashMap.Strict.InsOrd.toList + angles . map (prettyKeyValue colon) . Dhall.Map.toList prettyUnionLit - :: Pretty a => Text -> Expr s a -> InsOrdHashMap Text (Expr s a) -> Doc Ann + :: Pretty a => Text -> Expr s a -> Map Text (Expr s a) -> Doc Ann prettyUnionLit a b c = - angles (front : map adapt (Data.HashMap.Strict.InsOrd.toList c)) + angles (front : map adapt (Dhall.Map.toList c)) where front = prettyKeyValue equals (a, b) diff --git a/src/Dhall/TypeCheck.hs b/src/Dhall/TypeCheck.hs index bbd7c438f..d0744cd26 100644 --- a/src/Dhall/TypeCheck.hs +++ b/src/Dhall/TypeCheck.hs @@ -24,8 +24,8 @@ module Dhall.TypeCheck ( import Control.Exception (Exception) import Data.Data (Data(..)) import Data.Foldable (forM_, toList) -import Data.Monoid ((<>)) import Data.Sequence (Seq, ViewL(..)) +import Data.Semigroup (Semigroup(..)) import Data.Set (Set) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty(..)) @@ -36,8 +36,6 @@ import Dhall.Context (Context) import Dhall.Pretty (Ann, layoutOpts) import qualified Data.Foldable -import qualified Data.HashMap.Strict -import qualified Data.HashMap.Strict.InsOrd import qualified Data.Sequence import qualified Data.Set import qualified Data.Text as Text @@ -46,6 +44,7 @@ import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty import qualified Dhall.Context import qualified Dhall.Core import qualified Dhall.Diff +import qualified Dhall.Map import qualified Dhall.Pretty.Internal import qualified Dhall.Util @@ -425,7 +424,7 @@ typeWithA tpa = loop return (Pi "a" (Const Type) (Pi "_" (App List "a") - (App List (Record (Data.HashMap.Strict.InsOrd.fromList kts))) ) ) + (App List (Record (Dhall.Map.fromList kts))) ) ) loop _ ListReverse = do return (Pi "a" (Const Type) (Pi "_" (App List "a") (App List "a"))) loop _ Optional = do @@ -468,9 +467,9 @@ typeWithA tpa = loop (Pi "just" (Pi "_" "a" "optional") (Pi "nothing" "optional" "optional") ) loop ctx e@(Record kts ) = do - case Data.HashMap.Strict.InsOrd.toList kts of - [] -> return (Const Type) - (k0, t0):rest -> do + case Dhall.Map.uncons kts of + Nothing -> return (Const Type) + Just (k0, t0, rest) -> do s0 <- fmap Dhall.Core.normalize (loop ctx t0) c <- case s0 of Const Type -> @@ -479,7 +478,7 @@ typeWithA tpa = loop | Dhall.Core.judgmentallyEqual t0 (Const Type) -> return Kind _ -> Left (TypeError ctx e (InvalidFieldType k0 t0)) - let process (k, t) = do + let process k t = do s <- fmap Dhall.Core.normalize (loop ctx t) case s of Const Type -> @@ -495,11 +494,11 @@ typeWithA tpa = loop else Left (TypeError ctx e (FieldAnnotationMismatch k t k0 t0 Kind)) _ -> Left (TypeError ctx e (InvalidFieldType k t)) - mapM_ process rest + Dhall.Map.traverseWithKey_ process rest return (Const c) loop ctx e@(RecordLit kvs ) = do - case Data.HashMap.Strict.InsOrd.toList kvs of - [] -> return (Record Data.HashMap.Strict.InsOrd.empty) + case Dhall.Map.toList kvs of + [] -> return (Record mempty) (k0, v0):_ -> do t0 <- loop ctx v0 s0 <- fmap Dhall.Core.normalize (loop ctx t0) @@ -529,7 +528,7 @@ typeWithA tpa = loop Left (TypeError ctx e (InvalidField k t)) return t - kts <- Data.HashMap.Strict.InsOrd.traverseWithKey process kvs + kts <- Dhall.Map.traverseWithKey process kvs return (Record kts) loop ctx e@(Union kts ) = do let process k t = do @@ -538,20 +537,14 @@ typeWithA tpa = loop Const Type -> return () Const Kind -> return () _ -> Left (TypeError ctx e (InvalidAlternativeType k t)) - -- toList from insert-ordered-containers does some work to - -- ensure that the elements do follow insertion order. In this - -- instance, insertion order doesn't matter: we only need to - -- peek at each element to make sure it is well-typed. If - -- there are multiple type errors, it does not matter which - -- gets reported first here. - Data.HashMap.Strict.foldrWithKey (\ k t prev -> prev >> process k t) (Right ()) (Data.HashMap.Strict.InsOrd.toHashMap kts) + Dhall.Map.traverseWithKey_ process kts return (Const Type) loop ctx e@(UnionLit k v kts) = do - case Data.HashMap.Strict.InsOrd.lookup k kts of + case Dhall.Map.lookup k kts of Just _ -> Left (TypeError ctx e (DuplicateAlternative k)) Nothing -> return () t <- loop ctx v - let union = Union (Data.HashMap.Strict.InsOrd.insert k (Dhall.Core.normalize t) kts) + let union = Union (Dhall.Map.insert k (Dhall.Core.normalize t) kts) _ <- loop ctx union return union loop ctx e@(Combine kvsX kvsY) = do @@ -581,12 +574,12 @@ typeWithA tpa = loop let combineTypes ktsL ktsR = do let ksL = - Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsL) + Data.Set.fromList (Dhall.Map.keys ktsL) let ksR = - Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsR) + Data.Set.fromList (Dhall.Map.keys ktsR) let ks = Data.Set.union ksL ksR kts <- forM (toList ks) (\k -> do - case (Data.HashMap.Strict.InsOrd.lookup k ktsL, Data.HashMap.Strict.InsOrd.lookup k ktsR) of + case (Dhall.Map.lookup k ktsL, Dhall.Map.lookup k ktsR) of (Just (Record ktsL'), Just (Record ktsR')) -> do t <- combineTypes ktsL' ktsR' return (k, t) @@ -596,7 +589,7 @@ typeWithA tpa = loop return (k, t) _ -> do Left (TypeError ctx e (FieldCollision k)) ) - return (Record (Data.HashMap.Strict.InsOrd.fromList kts)) + return (Record (Dhall.Map.fromList kts)) combineTypes ktsX ktsY loop ctx e@(CombineTypes l r) = do @@ -627,12 +620,12 @@ typeWithA tpa = loop let combineTypes ktsL ktsR = do let ksL = - Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsL) + Data.Set.fromList (Dhall.Map.keys ktsL) let ksR = - Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsR) + Data.Set.fromList (Dhall.Map.keys ktsR) let ks = Data.Set.union ksL ksR forM_ (toList ks) (\k -> do - case (Data.HashMap.Strict.InsOrd.lookup k ktsL, Data.HashMap.Strict.InsOrd.lookup k ktsR) of + case (Dhall.Map.lookup k ktsL, Dhall.Map.lookup k ktsR) of (Just (Record ktsL'), Just (Record ktsR')) -> do combineTypes ktsL' ktsR' (Nothing, Just _) -> do @@ -670,7 +663,7 @@ typeWithA tpa = loop then return () else Left (TypeError ctx e (RecordMismatch '⫽' kvsX kvsY constX constY)) - return (Record (Data.HashMap.Strict.InsOrd.union ktsY ktsX)) + return (Record (Dhall.Map.union ktsY ktsX)) loop ctx e@(Merge kvsX kvsY (Just t)) = do _ <- loop ctx t @@ -678,13 +671,13 @@ typeWithA tpa = loop ktsX <- case tKvsX of Record kts -> return kts _ -> Left (TypeError ctx e (MustMergeARecord kvsX tKvsX)) - let ksX = Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsX) + let ksX = Data.Set.fromList (Dhall.Map.keys ktsX) tKvsY <- fmap Dhall.Core.normalize (loop ctx kvsY) ktsY <- case tKvsY of Union kts -> return kts _ -> Left (TypeError ctx e (MustMergeUnion kvsY tKvsY)) - let ksY = Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsY) + let ksY = Data.Set.fromList (Dhall.Map.keys ktsY) let diffX = Data.Set.difference ksX ksY let diffY = Data.Set.difference ksY ksX @@ -694,7 +687,7 @@ typeWithA tpa = loop else Left (TypeError ctx e (UnusedHandler diffX)) let process (kY, tY) = do - case Data.HashMap.Strict.InsOrd.lookup kY ktsX of + case Dhall.Map.lookup kY ktsX of Nothing -> Left (TypeError ctx e (MissingHandler diffY)) Just tX -> case tX of @@ -707,20 +700,20 @@ typeWithA tpa = loop then return () else Left (TypeError ctx e (InvalidHandlerOutputType kY t t'')) _ -> Left (TypeError ctx e (HandlerNotAFunction kY tX)) - mapM_ process (Data.HashMap.Strict.InsOrd.toList ktsY) + mapM_ process (Dhall.Map.toList ktsY) return t loop ctx e@(Merge kvsX kvsY Nothing) = do tKvsX <- fmap Dhall.Core.normalize (loop ctx kvsX) ktsX <- case tKvsX of Record kts -> return kts _ -> Left (TypeError ctx e (MustMergeARecord kvsX tKvsX)) - let ksX = Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsX) + let ksX = Data.Set.fromList (Dhall.Map.keys ktsX) tKvsY <- fmap Dhall.Core.normalize (loop ctx kvsY) ktsY <- case tKvsY of Union kts -> return kts _ -> Left (TypeError ctx e (MustMergeUnion kvsY tKvsY)) - let ksY = Data.Set.fromList (Data.HashMap.Strict.InsOrd.keys ktsY) + let ksY = Data.Set.fromList (Dhall.Map.keys ktsY) let diffX = Data.Set.difference ksX ksY let diffY = Data.Set.difference ksY ksX @@ -729,12 +722,12 @@ typeWithA tpa = loop then return () else Left (TypeError ctx e (UnusedHandler diffX)) - (kX, t) <- case Data.HashMap.Strict.InsOrd.toList ktsX of + (kX, t) <- case Dhall.Map.toList ktsX of [] -> Left (TypeError ctx e MissingMergeType) (kX, Pi y _ t):_ -> return (kX, Dhall.Core.shift (-1) (V y 0) t) (kX, tX ):_ -> Left (TypeError ctx e (HandlerNotAFunction kX tX)) let process (kY, tY) = do - case Data.HashMap.Strict.InsOrd.lookup kY ktsX of + case Dhall.Map.lookup kY ktsX of Nothing -> Left (TypeError ctx e (MissingHandler diffY)) Just tX -> case tX of @@ -747,7 +740,7 @@ typeWithA tpa = loop then return () else Left (TypeError ctx e (HandlerOutputTypeMismatch kX t kY t'')) _ -> Left (TypeError ctx e (HandlerNotAFunction kY tX)) - mapM_ process (Data.HashMap.Strict.InsOrd.toList ktsY) + mapM_ process (Dhall.Map.toList ktsY) return t loop ctx e@(Constructors t ) = do _ <- loop ctx t @@ -758,14 +751,14 @@ typeWithA tpa = loop let adapt k t_ = Pi k t_ (Union kts) - return (Record (Data.HashMap.Strict.InsOrd.mapWithKey adapt kts)) + return (Record (Dhall.Map.mapWithKey adapt kts)) loop ctx e@(Field r x ) = do t <- fmap Dhall.Core.normalize (loop ctx r) case t of Record kts -> do _ <- loop ctx t - case Data.HashMap.Strict.InsOrd.lookup x kts of + case Dhall.Map.lookup x kts of Just t' -> return t' Nothing -> Left (TypeError ctx e (MissingField x t)) _ -> do @@ -778,10 +771,10 @@ typeWithA tpa = loop _ <- loop ctx t let process k = - case Data.HashMap.Strict.InsOrd.lookup k kts of + case Dhall.Map.lookup k kts of Just t' -> return (k, t') Nothing -> Left (TypeError ctx e (MissingField k t)) - let adapt = Record . Data.HashMap.Strict.InsOrd.fromList + let adapt = Record . Dhall.Map.fromList fmap adapt (traverse process (Data.Set.toList xs)) _ -> do let text = Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabels xs) diff --git a/tests/QuickCheck.hs b/tests/QuickCheck.hs index 335400e4f..25d6308af 100644 --- a/tests/QuickCheck.hs +++ b/tests/QuickCheck.hs @@ -8,8 +8,7 @@ module QuickCheck where import Codec.Serialise (DeserialiseFailure(..)) import Control.Monad (guard) -import Data.Hashable (Hashable) -import Data.HashMap.Strict.InsOrd (InsOrdHashMap) +import Dhall.Map (Map) import Dhall.Core ( Chunks(..) , Const(..) @@ -33,7 +32,7 @@ import Test.Tasty (TestTree) import qualified Codec.Serialise import qualified Data.Coerce -import qualified Data.HashMap.Strict.InsOrd +import qualified Dhall.Map import qualified Data.Sequence import qualified Dhall.Binary import qualified Dhall.Core @@ -111,16 +110,16 @@ integer = , (1, fmap (\x -> x - (2 ^ (64 :: Int))) arbitrary) ] -instance (Eq k, Hashable k, Arbitrary k, Arbitrary v) => Arbitrary (InsOrdHashMap k v) where +instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map k v) where arbitrary = do n <- Test.QuickCheck.choose (0, 2) kvs <- Test.QuickCheck.vectorOf n ((,) <$> arbitrary <*> arbitrary) - return (Data.HashMap.Strict.InsOrd.fromList kvs) + return (Dhall.Map.fromList kvs) shrink = - map Data.HashMap.Strict.InsOrd.fromList + map Dhall.Map.fromList . shrink - . Data.HashMap.Strict.InsOrd.toList + . Dhall.Map.toList instance (Arbitrary s, Arbitrary a) => Arbitrary (Chunks s a) where arbitrary = do diff --git a/tests/Regression.hs b/tests/Regression.hs index b8198a101..122d79287 100644 --- a/tests/Regression.hs +++ b/tests/Regression.hs @@ -5,13 +5,13 @@ module Regression where import qualified Control.Exception -import qualified Data.HashMap.Strict.InsOrd import qualified Data.Text.Lazy.IO import qualified Data.Text.Prettyprint.Doc import qualified Data.Text.Prettyprint.Doc.Render.Text import qualified Dhall import qualified Dhall.Context import qualified Dhall.Core +import qualified Dhall.Map import qualified Dhall.Parser import qualified Dhall.Pretty import qualified Dhall.TypeCheck @@ -52,21 +52,25 @@ data Foo = Foo Integer Bool | Bar Bool Bool Bool | Baz Integer Integer unnamedFields :: TestTree unnamedFields = Test.Tasty.HUnit.testCase "Unnamed Fields" (do let ty = Dhall.auto :: Dhall.Type Foo - Test.Tasty.HUnit.assertEqual "Good type" (Dhall.expected ty) (Dhall.Core.Union ( - Data.HashMap.Strict.InsOrd.fromList [ - ("Bar",Dhall.Core.Record (Data.HashMap.Strict.InsOrd.fromList [ - ("_1",Dhall.Core.Bool),("_2",Dhall.Core.Bool),("_3",Dhall.Core.Bool)])) - , ("Baz",Dhall.Core.Record (Data.HashMap.Strict.InsOrd.fromList [ - ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Integer)])) - ,("Foo",Dhall.Core.Record (Data.HashMap.Strict.InsOrd.fromList [ - ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool)]))])) + Test.Tasty.HUnit.assertEqual "Good type" (Dhall.expected ty) + (Dhall.Core.Union + (Dhall.Map.fromList + [ ("Foo",Dhall.Core.Record (Dhall.Map.fromList [ + ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool)])) + , ("Bar",Dhall.Core.Record (Dhall.Map.fromList [ + ("_1",Dhall.Core.Bool),("_2",Dhall.Core.Bool),("_3",Dhall.Core.Bool)])) + , ("Baz",Dhall.Core.Record (Dhall.Map.fromList [ + ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Integer)])) + ] + ) + ) let inj = Dhall.inject :: Dhall.InputType Foo Test.Tasty.HUnit.assertEqual "Good Inject" (Dhall.declared inj) (Dhall.expected ty) let tu_ty = Dhall.auto :: Dhall.Type (Integer, Bool) Test.Tasty.HUnit.assertEqual "Auto Tuple" (Dhall.expected tu_ty) (Dhall.Core.Record ( - Data.HashMap.Strict.InsOrd.fromList [ ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool) ])) + Dhall.Map.fromList [ ("_1",Dhall.Core.Integer),("_2",Dhall.Core.Bool) ])) let tu_in = Dhall.inject :: Dhall.InputType (Integer, Bool) Test.Tasty.HUnit.assertEqual "Inj. Tuple" (Dhall.declared tu_in) (Dhall.expected tu_ty)