* Benchmark Prelude files
* Add issue 108 example
* Some cleaning up
* Remove printing of files
* Add bounds
* Clean cabal formatting
* Using strict Text instead of lazy Text
* Fixing compilation errors
* Update tests
* Cleanup
* Revert benchmark merge
* Update comments to replace the mention of Builder to Text
In tests on Dhall configs we use at work, I saw speedups between 33–90% on
extremely complicated configs with this change.
It mostly just adds a line calling `normalize`, but also threads the Normalizer
through a bunch of places to make sure we normalize properly for the context.
... as standardized in https://github.com/dhall-lang/dhall-lang/pull/141
Now `Natural`s no longer require a leading `+` and non-negative `Integer`s
require a leading `+`
This also adds a `doctest` test suite to prevent regressions in haddock
examples
Related to #346
This fixes the `GenericInject` instance for a sum type with two
constructors to include the type of the alternative constructor. For
example, before this change you would get the following incorrect
conversion:
```
$ cabal repl lib:dhall
>>> :set -XDeriveGeneric
>>> :set -XDeriveAnyClass
>>> data Amount = Debit Scientific | Credit Scientific deriving (Show, Generic, Inject, Interpret)
>>> Dhall.Core.pretty (embed inject (Debit 5.45))
"< Debit = { _1 = 5.45 } >"
```
... which is missing the `Credit` alternative.
After this change you get the correct result:
```
< Debit = { _1 = 5.45 } | Credit : { _1 : Double } >
```
The long-term motivation for this change is so that we can eventually use a
separate `attoparsec`-based lexing step to greatly increase parsing speed since
the `trifecta`/`parsers` API doesn't allow tokens other than `Char`.
The secondary motivation for this is that `megaparsec` is a smaller dependency
that is more actively maintained.
This fixes all of the build built-ins to match the standard semantics
The easiest way to illustrate the problem is the following example from
the test suite:
```haskell
λ(id : ∀(a : Type) → a → a)
→ Natural/build
( λ(natural : Type)
→ λ(succ : natural → natural)
→ λ(zero : natural)
→ id natural (succ zero)
)
```
According to the standard semantics that should normalize to:
```haskell
λ(id : ∀(a : Type) → a → a) → id Natural +1
```
... but before this change it was not reducing at all. After this
change it reduces correctly.
However, there is a further issue, which is that correctly implementing
the semantics leads to poor time complexity for `List/build` since it is
specified in terms of repeatedly prepending a single element, which
leads to quadratic time complexity since lists are implemented in terms
of `Vector` under the hood.
You might think that you could use the efficient approach for
expressions like this:
```haskell
List/build
Bool
( λ(list : Type)
→ λ(cons : Bool → list → list)
→ λ(nil : list)
→ cons True (cons False nil)
)
```
... and then fall back on the slower approach for more interesting cases
such as this:
```haskell
λ(id : ∀(a : Type) → a → a)
→ List/build
Bool
( λ(list : Type)
→ λ(cons : Bool → list → list)
→ λ(nil : list)
→ id list (cons True (cons False nil))
)
```
... but that does not work either! The reason why is that very often
you don't use `List/build` directly and instead use it indirectly via
helper functions such as `Prelude/List/concat`:
```haskell
let concat : ∀(a : Type) → List (List a) → List a
= λ(a : Type)
→ λ(xss : List (List a))
→ List/build
a
( λ(list : Type)
→ λ(cons : a → list → list)
→ λ(nil : list)
→ List/fold
(List a)
xss
list
( λ(xs : List a)
→ λ(ys : list)
→ List/fold
a
xs
list
cons
ys
)
nil
)
in concat
```
... so what happens is that if you try to normalize something like:
```haskell
concat Text [["Example"]]
```
... the `concat` function will be normalized first, which will cause the
`List/build` to be normalized when its argument is still abstract, which will
trigger the slow path for the semantics.
Consequently, this change also modifies Dhall lists to be backed by
`Data.Sequence.Seq` instead of `Data.Vector.Vector`, so that
`List/build` can always use the correct implementation of semantics
in linear time while still implementing other operations on lists
reasonably efficiently.
This in turn triggers another change to the `OptionalLit` constructor
to use `Maybe` to store the payload instead of `Vector`. The only
reason that `OptionalLit` originally used `Vector` was so that
`List/head` and `List/last` could be implemented as just a slice into
the `ListLit` vector, but now that it's not a vector any longer it's
simpler to just use a more accurate `Maybe` type to represent the
payload.
Fixes https://github.com/dhall-lang/dhall-lang/issues/86
This change has two benefits:
* Users of the Haskell API can now marshal Dhall values of type `Double` into
Haskell values of type `Scientific`
* The `dhall` executable no longer loses precision when dealing with
values that have a large exponent (see the newly added test)
Related to #244
This updates Dhall's syntax tree to use an insert-ordered hashmap to store
record fields and union alternatives. This in turn implies that they will be
formatted in the same order that they were originally parsed.
This is a breaking change to the API due to changing the type of map used in the
syntax tree.
Fixes#216
This changes the internal representation of `TextLit` to be able to
store an interpolated string literal. Preserving string interpolation in
the syntax tree means that `dhall-format` can also preserve
interpolation.
This also simplifies a lot of the string-interpolation-related code,
which is now simpler and more strongly typed.
Maps unnamed data fields to the positional record keys. For example:
```haskell
data Foo = Foo Bool Integer Natural deriving (Generic, Interpret)
```
... is mapped to this Dhall data type:
```haskell
Record { _1 : Bool, _2 : Integer, _3 : Natural }
```
This replaces all uses of `NeatInterpolation` with either multi-line
strings or `unlines`. This allows Dhall to be compiled without using
Template Haskell, which in turn enables cross-compilation
Added a function that allows doing `input` from a closed
Dhall `Expr` instead of text. This is hugely useful when
working with Dhall in AST level (for example, using custom
types / normalization). For example, suppose that you have
built a custom primitive that requires a record as an argument.
With `rawInput` you can just extract the record into a Haskell
data type and process it without need to work with maps and other
bits of AST.
For context of this commit, see #79 (and also #26).
Consider the following Haskell program:
```
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import Dhall hiding (auto)
import qualified Data.Text.Lazy
interpretOptions :: InterpretOptions
interpretOptions = defaultInterpretOptions
{ fieldModifier = Data.Text.Lazy.dropWhile (== '_') }
data GitRepo = GitRepo
{ _host :: Text
, _repo :: Text
} deriving (Generic, Interpret, Show)
data BoxConfig = BoxConfig
{ _userName :: Text
, _dotfilesRepo :: Vector GitRepo
} deriving (Generic, Interpret, Show)
main :: IO ()
main = do
x <- Dhall.input (autoWith interpretOptions) "./config"
print (x :: BoxConfig)
```
Before this change the above program attempts to decode a value of type:
```
{ userName : Text, dotfilesRepo : List { _host : Text, _repo : Text } }
```
... when it should be decoding a value of type:
```
{ userName : Text, dotfilesRepo : List { host : Text, repo : Text } }
```
This change ensures that `InterpretOptions` correctly propagate to elements of
`List` or `Optional` values
Consider the following program which marshals a Dhall record into Haskell:
```haskell
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import Dhall hiding (auto)
import qualified Data.Text.Lazy
interpretOptions :: InterpretOptions
interpretOptions = defaultInterpretOptions
{ fieldModifier = Data.Text.Lazy.dropWhile (== '_') }
data GitRepo = GitRepo
{ _host :: Text
, _repo :: Text
} deriving (Generic, Interpret, Show)
data BoxConfig = BoxConfig
{ _userName :: Text
, _dotfilesRepo :: GitRepo
} deriving (Generic, Interpret, Show)
main :: IO ()
main = do
x <- Dhall.input (autoWith interpretOptions) "./config"
print (x :: BoxConfig)
```
The above program is a common pattern when mixing Dhall records with lenses
(which typically prefix the original fields with "_").
Before this change, the above program expects a record of the following type:
```
{ userName : Text, dotfilesRepo : { _host : Text, _repo : Text } }
```
Note that the sub-record ignores the `InterpretOptions` and incorrectly includes
the underscore in the expected field names.
This change fixes the derived `Interpret` instance for records to correctly
thread `InterpretOptions` to nested records.
This required a change to the `auto` method of the `Interpret` class to
accept `InterpretOptions`, otherwise there is no way to supply the
`InterpretOptions` record to sub-records. This modified `auto` method is now
called `autoWith`. I still include an `auto` function that uses
`defaultInterpretOptions` consistent with the old behavior.
This adds a new `deriveAuto` utility that you can customize with
`InterpretOptions` in order to transform the expected field or constructor
labels that Dhall expects
The most common use of this is to support data types that prefix field names
with underscores for lens support