Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement with without syntactic sugar #2055

Merged
merged 3 commits into from Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion dhall/dhall-lang
Submodule dhall-lang updated 91 files
+42 −0 CHANGELOG.md
+16 −16 Prelude/Bool/package.dhall
+2 −2 Prelude/Double/package.dhall
+4 −4 Prelude/Function/package.dhall
+2 −2 Prelude/Integer/add.dhall
+2 −2 Prelude/Integer/equal.dhall
+4 −4 Prelude/Integer/greaterThan.dhall
+2 −2 Prelude/Integer/greaterThanEqual.dhall
+2 −2 Prelude/Integer/lessThan.dhall
+8 −8 Prelude/Integer/lessThanEqual.dhall
+2 −2 Prelude/Integer/multiply.dhall
+2 −2 Prelude/Integer/negative.dhall
+2 −2 Prelude/Integer/nonNegative.dhall
+36 −36 Prelude/Integer/package.dhall
+4 −4 Prelude/Integer/positive.dhall
+2 −2 Prelude/Integer/subtract.dhall
+2 −2 Prelude/Integer/toNatural.dhall
+2 −2 Prelude/JSON/Tagged.dhall
+4 −4 Prelude/JSON/array.dhall
+2 −2 Prelude/JSON/bool.dhall
+28 −28 Prelude/JSON/core.dhall
+0 −57 Prelude/JSON/core.dhall.dhall
+2 −2 Prelude/JSON/double.dhall
+2 −2 Prelude/JSON/integer.dhall
+2 −2 Prelude/JSON/keyText.dhall
+2 −2 Prelude/JSON/keyValue.dhall
+2 −2 Prelude/JSON/natural.dhall
+2 −2 Prelude/JSON/null.dhall
+4 −4 Prelude/JSON/number.dhall
+4 −4 Prelude/JSON/object.dhall
+4 −4 Prelude/JSON/omitNullFields.dhall
+10 −10 Prelude/JSON/package.dhall
+4 −4 Prelude/JSON/render.dhall
+10 −10 Prelude/JSON/renderAs.dhall
+2 −2 Prelude/JSON/renderInteger.dhall
+0 −23 Prelude/JSON/renderInteger.dhall.dhall
+4 −4 Prelude/JSON/renderYAML.dhall
+2 −2 Prelude/JSON/string.dhall
+4 −4 Prelude/JSON/tagInline.dhall
+4 −4 Prelude/JSON/tagNested.dhall
+2 −2 Prelude/List/drop.dhall
+2 −2 Prelude/List/index.dhall
+54 −54 Prelude/List/package.dhall
+2 −2 Prelude/List/take.dhall
+4 −4 Prelude/List/unpackOptionals.dhall
+2 −2 Prelude/List/zip.dhall
+2 −2 Prelude/Location/package.dhall
+2 −2 Prelude/Map/empty.dhall
+4 −4 Prelude/Map/keys.dhall
+6 −6 Prelude/Map/map.dhall
+3 −0 Prelude/Map/package.dhall
+39 −0 Prelude/Map/unpackOptionals.dhall
+6 −6 Prelude/Map/values.dhall
+2 −2 Prelude/Natural/equal.dhall
+2 −2 Prelude/Natural/greaterThan.dhall
+2 −2 Prelude/Natural/greaterThanEqual.dhall
+4 −4 Prelude/Natural/lessThan.dhall
+4 −4 Prelude/Natural/listMax.dhall
+4 −4 Prelude/Natural/listMin.dhall
+2 −2 Prelude/Natural/max.dhall
+2 −2 Prelude/Natural/min.dhall
+44 −44 Prelude/Natural/package.dhall
+6 −6 Prelude/Natural/sort.dhall
+28 −28 Prelude/Optional/package.dhall
+18 −18 Prelude/Text/package.dhall
+4 −4 Prelude/Text/replicate.dhall
+2 −2 Prelude/Text/spaces.dhall
+4 −4 Prelude/XML/element.dhall
+4 −4 Prelude/XML/leaf.dhall
+14 −14 Prelude/XML/package.dhall
+6 −6 Prelude/XML/render.dhall
+2 −2 Prelude/XML/text.dhall
+3 −3 Prelude/package.dhall
+582 −489 docs/references/Built-in-types.md
+36 −3 docs/tutorials/Language-Tour.md
+1 −1 nixops/logical.nix
+32 −11 standard/beta-normalization.md
+0 −64 standard/record.md
+34 −12 standard/type-inference.md
+1 −1 standard/versioning.md
+3 −0 tests/normalization/success/unit/WithCreateIntermediateRecordsA.dhall
+1 −0 tests/normalization/success/unit/WithCreateIntermediateRecordsB.dhall
+1 −2 tests/normalization/success/unit/WithDesugarA.dhall
+1 −1 tests/normalization/success/unit/WithDesugarB.dhall
+0 −5 tests/normalization/success/unit/WithUnderscoreA.dhall
+0 −1 tests/normalization/success/unit/WithUnderscoreB.dhall
+1 −0 tests/type-inference/failure/unit/WithNotRecord.dhall
+0 −5 tests/type-inference/failure/unit/WithUnderscore.dhall
+5 −0 tests/type-inference/success/preludeB.dhall
+3 −0 tests/type-inference/success/unit/WithCreateIntermediateRecordsA.dhall
+1 −0 tests/type-inference/success/unit/WithCreateIntermediateRecordsB.dhall
25 changes: 23 additions & 2 deletions dhall/src/Dhall/Diff.hs
Expand Up @@ -1032,8 +1032,29 @@ diffApplicationExpression l r =
diffWithExpression l r

diffWithExpression :: (Eq a, Pretty a) => Expr Void a -> Expr Void a -> Diff
diffWithExpression l@With{} r@With{} =
diffWithExpression (Syntax.desugarWith l) (Syntax.desugarWith r)
diffWithExpression (With eL ksL vL) (With eR ksR vR) =
align
( format " " (diffImportExpression eL eR)
Gabriella439 marked this conversation as resolved.
Show resolved Hide resolved
<> "with "
<> align
( format " " (diffPath ksL ksR)
<> "= "
<> diffOperatorExpression vL vR
)
)
where
diffPath (kL :| []) (kR :| []) =
diffLabel kL kR
diffPath (kL₀ :| kL₁ : ksL') (kR₀ :| kR₁ : ksR') =
format "" (diffLabel kL₀ kR₀)
<> dot
<> diffPath (kL₁ :| ksL') (kR₁ :| ksR')
diffPath (kL :| []) (kR₀ :| kR₁ : ksR') =
format "" (diffLabel kL kR₀)
<> plus (foldMap (\k -> dot <> token (Internal.prettyLabel k)) (kR₁ :| ksR'))
diffPath (kL₀ :| kL₁ : ksL') (kR :| []) =
format "" (diffLabel kL₀ kR)
<> minus (foldMap (\k -> dot <> token (Internal.prettyLabel k)) (kL₁ :| ksL'))
diffWithExpression l r@With{} =
mismatch l r
diffWithExpression l@With{} r =
Expand Down
36 changes: 26 additions & 10 deletions dhall/src/Dhall/Eval.hs
Expand Up @@ -50,14 +50,15 @@ module Dhall.Eval (
, textShow
) where

import Data.Foldable (foldr', toList)
import Data.Sequence (Seq, ViewL (..), ViewR (..))
import Data.Text (Text)
import Data.Void (Void)
import Dhall.Map (Map)
import Dhall.Set (Set)
import GHC.Natural (Natural)
import Prelude hiding (succ)
import Data.Foldable (foldr', toList)
import Data.List.NonEmpty (NonEmpty(..))
import Data.Sequence (Seq, ViewL (..), ViewR (..))
import Data.Text (Text)
import Data.Void (Void)
import Dhall.Map (Map)
import Dhall.Set (Set)
import GHC.Natural (Natural)
import Prelude hiding (succ)

import Dhall.Syntax
( Binding (..)
Expand Down Expand Up @@ -219,6 +220,7 @@ data Val a
| VProject !(Val a) !(Either (Set Text) (Val a))
| VAssert !(Val a)
| VEquivalent !(Val a) !(Val a)
| VWith !(Val a) (NonEmpty Text) !(Val a)
| VEmbed a

-- | For use with "Text.Show.Functions".
Expand Down Expand Up @@ -383,6 +385,18 @@ vProjectByFields env t ks =
t' ->
VProject t' (Left ks)

vWith :: Val a -> NonEmpty Text -> Val a -> Val a
vWith (VRecordLit kvs) (k :| [] ) v = VRecordLit (Map.insert k v kvs)
vWith (VRecordLit kvs) (k₀ :| k₁ : ks) v = VRecordLit (Map.insert k₀ e₂ kvs)
where
e₁ =
case Map.lookup k₀ kvs of
Nothing -> VRecordLit mempty
Just e₁' -> e₁'

e₂ = vWith e₁ (k₁ :| ks) v
vWith e₀ ks v₀ = VWith e₀ ks v₀

eval :: forall a. Eq a => Environment a -> Expr Void a -> Val a
eval !env t0 =
case t0 of
Expand Down Expand Up @@ -725,8 +739,8 @@ eval !env t0 =
VAssert (eval env t)
Equivalent t u ->
VEquivalent (eval env t) (eval env u)
e@With{} ->
eval env (Syntax.desugarWith e)
With e₀ ks v ->
vWith (eval env e₀) ks (eval env v)
Note _ e ->
eval env e
ImportAlt t _ ->
Expand Down Expand Up @@ -1118,6 +1132,8 @@ quote !env !t0 =
Assert (quote env t)
VEquivalent t u ->
Equivalent (quote env t) (quote env u)
VWith e ks v ->
With (quote env e) ks (quote env v)
VInject m k Nothing ->
Field (Union (fmap (fmap (quote env)) m)) $ Syntax.makeFieldSelection k
VInject m k (Just t) ->
Expand Down
23 changes: 21 additions & 2 deletions dhall/src/Dhall/Normalize.hs
Expand Up @@ -23,6 +23,7 @@ module Dhall.Normalize (
import Control.Applicative (empty)
import Data.Foldable
import Data.Functor.Identity (Identity (..))
import Data.List.NonEmpty (NonEmpty(..))
import Data.Sequence (ViewL (..), ViewR (..))
import Data.Traversable
import Instances.TH.Lift ()
Expand Down Expand Up @@ -613,8 +614,26 @@ normalizeWithM ctx e0 = loop (Syntax.denote e0)
r' <- loop r

pure (Equivalent l' r')
With e' k v ->
loop (Syntax.desugarWith (With e' k v))
With e ks v -> do
e' <- loop e
v' <- loop v

case e' of
RecordLit kvs ->
case ks of
k :| [] ->
return (RecordLit (Dhall.Map.insert k (Syntax.makeRecordField v') kvs))
k₀ :| k₁ : ks' -> do
let e₁ =
case Dhall.Map.lookup k₀ kvs of
Nothing -> RecordLit mempty
Just r -> Syntax.recordFieldValue r

e₂ <- loop (With e₁ (k₁ :| ks') v')

return (RecordLit (Dhall.Map.insert k₀ (Syntax.makeRecordField e₂) kvs))
_ ->
return (With e' ks v')
Note _ e' -> loop e'
ImportAlt l _r -> loop l
Embed a -> pure (Embed a)
Expand Down
65 changes: 63 additions & 2 deletions dhall/src/Dhall/TypeCheck.hs
Expand Up @@ -1251,8 +1251,27 @@ infer typer = loop

return (VConst Type)

e@With{} ->
loop ctx (Syntax.desugarWith e)
With e ks v -> do
tE' <- loop ctx e

kTs' <- case tE' of
VRecord kTs' -> return kTs'
_ -> die (NotWithARecord e (quote names tE'))

case ks of
k :| [] -> do
tV' <- loop ctx v

return (VRecord (Dhall.Map.insert k tV' kTs'))
k₀ :| k₁ : ks' -> do
let e₁ =
if Dhall.Map.member k₀ kTs'
then Field e (Syntax.makeFieldSelection k₀)
else RecordLit mempty

tV' <- loop ctx (With e₁ (k₁ :| ks') v)

return (VRecord (Dhall.Map.insert k₀ tV' kTs'))

Note s e ->
case loop ctx e of
Expand Down Expand Up @@ -1343,6 +1362,7 @@ data TypeMessage s a
| NotAnEquivalence (Expr s a)
| IncomparableExpression (Expr s a)
| EquivalenceTypeMismatch (Expr s a) (Expr s a) (Expr s a) (Expr s a)
| NotWithARecord (Expr s a) (Expr s a)
| CantAnd (Expr s a) (Expr s a)
| CantOr (Expr s a) (Expr s a)
| CantEQ (Expr s a) (Expr s a)
Expand Down Expand Up @@ -4238,6 +4258,45 @@ prettyTypeMessage (EquivalenceTypeMismatch l _L r _R) = ErrorMessages {..}
\ \n\
\" <> insert _R <> "\n"

prettyTypeMessage (NotWithARecord expr0 expr1) = ErrorMessages {..}
where
short = "❰with❱ only works on records"

long =
"Explanation: You can use ❰with❱ to update a record, like this: \n\
\ \n\
\ \n\
\ ┌─────────────────────────┐ \n\
\ │ { a = 5 } with b = 10 │ This is valid because ❰{ a = 5}❱ is a record \n\
\ └────────────────────────┘ \n\
\ \n\
\ ┌──────────────────────────────────────────┐ \n\
\ │ λ(r : { a : Natural }) → r with b = 10 │ This is also valid because \n\
\ └──────────────────────────────────────────┘ ❰r❱ is a record \n\
\ \n\
\ \n\
\... but you cannot use ❰with❱ to update an expression that is not a record. For\n\
\example, the following expression is " <> _NOT <> " valid: \n\
\ \n\
\ \n\
\ ┌───────────────┐ \n\
\ │ 1 with b = 10 │ Invalid: ❰1❱ is not a record \n\
\ └───────────────┘ \n\
\ \n\
\ \n\
\You tried to update the following expressions: \n\
\ \n\
\" <> txt0 <> "\n\
\ \n\
\... which has type\n\
\ \n\
\" <> txt1 <> "\n\
\ \n\
\... which is not a record type\n"
where
txt0 = insert expr0
txt1 = insert expr1

prettyTypeMessage (CantAnd expr0 expr1) =
buildBooleanOperator "&&" expr0 expr1

Expand Down Expand Up @@ -4649,6 +4708,8 @@ messageExpressions f m = case m of
IncomparableExpression <$> f a
EquivalenceTypeMismatch a b c d ->
EquivalenceTypeMismatch <$> f a <*> f b <*> f c <*> f d
NotWithARecord a b ->
NotWithARecord <$> f a <*> f b
CantAnd a b ->
CantAnd <$> f a <*> f b
CantOr a b ->
Expand Down
5 changes: 5 additions & 0 deletions dhall/tests/diff/with.txt
@@ -0,0 +1,5 @@
λ(… : { …
})
→ … with …+ .c.d
= - 2
+ 3
1 change: 1 addition & 0 deletions dhall/tests/diff/withA.dhall
@@ -0,0 +1 @@
λ(r : { a : Natural }) → r with b = 2
1 change: 1 addition & 0 deletions dhall/tests/diff/withB.dhall
@@ -0,0 +1 @@
λ(r : { a : Natural }) → r with b.c.d = 3