v9.0.0
Breaking changes:
-
Remove old
Optional
literal syntaxThis is phase 2 of removing support for the old
List
-likeOptional
literal
syntax.This phase removes the old
Optional
literals from the language. You now
must useSome
orNone
.For more details, including migration instructions, see:
Migration: Deprecation of oldOptional
literal syntax -
Forbid surrogate pairs and non-characters
Dhall no longer supports surrogate pairs within escape sequences. In other
words, something like this is no longer valid:"\uD834\uDD1E"
... and you must instead use a braced escape sequence to represent a Unicode
character that would have previously required a surrogate pair:"\u{1D11E}"
Dhall also no longer supports escape sequences for non-characters, so
something like this is also no longer valid:"\uFFFF"
Surrogate pairs and non-characters are also now explicitly forbidden within
the source code (i.e. within comments or unescaped text literals), but these
were already forbidden before. Dhall source code has to be valid UTF8, which
already disallows those characters. -
Add
toMap
keyword to create homogeneous maps from recordsYou can now create an association list (a.k.a. a
Map
) from a Dhall record if
all of the values stored within the record have the same type. For
example:toMap { foo = 1, bar = 2 } = [ { mapKey = "foo", mapValue = 1 }, { mapKey = "bar", mapValue = 2 } ]
This allows a Dhall binding to a configuration format to accept a list of
key-value pairs if it doesn't know in advance what keys to expect, while
still permitting the user to specify the key-value pairs using record-like
syntax.Two other features within this same release take advantage of this:
-
You can now specify custom headers for imports using the record
generated bytoMap
, like this:https://example.com/foo using toMap { Authorization = "token ${env:GITHUB_TOKEN as Text }" }
-
You can specify key-value pairs for the
JSON
type just added to the
Prelude usingtoMap
, too:let JSON = https://prelude.dhall-lang.org/JSON/package.dhall in JSON.object (toMap { foo = JSON.number 1.0, bar = JSON.string "baz" })
This is a technically breaking change because
toMap
is now a reserved
keyword, but in practice most users will not be affected unless they used
that label before this change. -
-
Beta-normalization: Sort the fields of a record projection
Normalization will now sort the fields of a record projection if it cannot
be further reduced. For example, this expression:λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ c, a }
... now normalizes to:
λ(x : { a : Bool, b : Bool, c : Bool }) → x.{ a, c }
This is a technically breaking change because it might perturb the hash of
any expression that contains an irreducible record projection, but in
practice this should not affect most users.
New features:
-
Implement importing paths
as Location
Dhall now permits reflection on fully resolved import paths so that these
paths remain up-to-date no matter where the configuration file is
interpreted from.For example, suppose that you store the following configuration file at
/home/john/example.dhall
:{ packagePath = "./purescript-simple-json" }
... where
packagePath
is intended to point to
/home/john/purescript-simple-json
.... but then you use that to configure a program running with a different
current working directory, such as:PWD=/home/alice/
. That program will
fail to resolve the package path because/home/alice/purescript-simple-json
does not exist.However, if you change the configuration to:
{ packagePath = ./purescript-simple-json as Location }
Then the interpreter will replace the import with an expression encoding the
absolute path to the import, generating an expression equivalent to this:let Location = https://prelude.dhall-lang.org/Location/Type in { packagePath = Location.Local "/home/john/purescript-simple-json" }
... so that the Dhall configuration file can be used to configure a program
running within any working directory.If the same file were hosted at
https://example.com/john/example.dhall
then
the expression would evaluate to:let Location = https://prelude.dhall-lang.org/Location/Type in { packagePath = Location.Remote "https://example.com/john/purescript-simple-json" }
-
Allow all RFC3986-compliant URLs
Now all URLs are valid imports.
For example, before this change
https://example.com
was not a valid import
due to not having any path components and after this change URLs without
paths are valid.This change also enables:
- URLs with empty path components (i.e.
https://example.com///
) - Path components with unquoted special characters, such as
=
- URLs with empty path components (i.e.
-
Generalize empty list annotations
You can now annotate an empty list with a type synonym, like this:
let Example = List Natural in [] : Example
Before this change, the
List
in: List
was part of the grammar for empty
lists, and you could only create a type synonym for the list element type,
but not the list type as a whole. Now you can create a type synonym for the
list type. -
Add
Map
type and utility functions to PreludeThe Prelude is now enshrining the Dhall idiom of using
List { mapKey : Text, mapValue : a }
to represent homogeneous maps by
adding basic types and utilities for working with values of that type.This change pairs well with the following matching changes in this release:
-
Use multihash for cache filenames
Dhall caches imports protected by semantic integrity checks underneath
${XDG_CACHE_HOME}/dhall
or~/.cache/dhall
and this change affects the
names of the cache files, which are now preceded with the four characters
1220
to reflect
the multi-hash standard.This change means that the interpreter will not reuse old cache files when
upgrading from an older release, so the cache will be rebuilt upon the first
run of the interpreter. However, this is not a breaking change as this does
not change the final result interpreting a protection protected by a semantic
integrity check. -
Add support for braced escape sequences
You can now escape Unicode characters using braces, like this:
"Musical symbol G clef: \u{1D11E}"
This allows Dhall to escape Unicode characters with code points greater than
0xFFFF
without the use of surrogate pairs. This is necessary given that
surrogate pair escape sequences are now forbidden within this same release. -
Prelude: Add standard representation for weakly-typed JSON values
Utilities like
dhall-to-{json,yaml}
and{json,yaml}-to-dhall
have up until
now only supported Dhall types with schemas known ahead-of-time. However,
some configuration file formats support fields that can store arbitrary JSON
code (such as arbitrary JSON that the configuration intends to "pass through"
to configure another step).This change adds a canonical type to the Prelude for representing an arbitrary
JSON value and utilities for creating such JSON values. For example:let JSON = https://prelude.dhall-lang.org/JSON/package.dhall in JSON.object ( toMap { foo = JSON.null , bar = JSON.array [ JSON.number 1.0, JSON.bool True ] } )
Also, the matching release of the
dhall-json
package supports this
weakly-typed representation anywhere within the schema when converting
either way between JSON/YAML and Dhall configuration files. -
Use
Prelude/Map
for import headersYou can now use a value of type
List { mapValue : Text, mapValue : Text }
to represent custom headers within an import'susing
clause instead of
List { header : Text, value : Text }
. For example:https://example.com/foo using [ { mapKey = "Authorization" , mapValue = "token ${env:GITHUB_TOKEN as Text}" } ]
... or using the new
toMap
keyword:https://example.com/foo using toMap { Authorization = "token ${env:GITHUB_TOKEN as Text}" }
The old
header
/value
form is still supported, so this is not a breaking
change. However, at some point in the future we may initiate the process of
deprecatingheader
/value
support. -
There is now a
Prelude/XML
package that you can use to represent and
render a subset of XML values using Dhall. This will eventually be used to
power adhall-to-xml
utility.For example:
let XML = https://prelude.dhall-lang.org/XML/package.dhall in XML.render (XML.leaf { name = "foobar", attributes = XML.emptyAttributes }) = "<foobar/>"
Other changes:
-
Fixes and improvements to the standard:
- Use RFC3986 section 5 URL resolution algorithm
- Simpler way of incorporating RFC 3986 resolution
- Only allow valid HTTP(S) reg-names
- Treat "multi-lets" as syntactic sugar
- Clarify how semantic integrity checks work for
as Text
- Normalize projection-by-expression via projection
- Fix mistake in
let
type-checking documentation - Fix type inference rule for projection by type
- Tidy up record projection
- Beta normalization: Use
=
instead of⇥
with thekeys
helper - Binary encoding: Use 28 for empty lists with non-List annotations
- Fix grammar for empty list literals
- Left factor grammar for domains
dhall.abnf
: Replace (ALPHA / DIGIT
) withALPHANUM
- Fix first-application-expression rule
- Fix type-inference for
toMap
-
Fixes and improvements to standard test suite:
- Test for fetching imports from cache
- Add a bunch of binary decode tests
- Fix
parenthesizeUsing
parser test - Fix projection by expression parser test and add more
- Commuting operators should not normalize commuted
- Fix normalization test for
Prelude/JSON/Type
- Fix normalization tests containing unbound variables
- Fix
as Location
tests - Add test to ensure that
constructors
doesn't typecheck anymore - Add failure tests for deprecated
Optional
literal syntax - Fix
toMap
normalization test - Fix
ListLitEmptyPrecedence
parsing test potPourriB.dhallb
: Fix encoding of query string- Add CBOR diagnostic files for ease of code review
-
Fixes and improvements to the Prelude: