Initial Dhall functions
Add functions for representing the JSON subset of Preserves in the Dhall configuration language. https://dhall-lang.org/
This commit is contained in:
parent
1668fdc6dd
commit
2ff489d975
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
Here you may find:
|
Here you may find:
|
||||||
|
|
||||||
|
- [dhall](dhall/), functions for converting Dhall values to a corresponding
|
||||||
|
subset of Preserves.
|
||||||
|
|
||||||
- [javascript](javascript/), an implementation in TypeScript,
|
- [javascript](javascript/), an implementation in TypeScript,
|
||||||
compiling to JavaScript, for node.js and the Browser.
|
compiling to JavaScript, for node.js and the Browser.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
env:DHALL_PRELUDE
|
||||||
|
? https://prelude.dhall-lang.org/v20.2.0/package.dhall
|
||||||
|
sha256:a6036bc38d883450598d1de7c98ead113196fe2db02e9733855668b18096f07b
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Dhall
|
||||||
|
|
||||||
|
Not a true implementation of Preserves, but functions for translating Dhall
|
||||||
|
values to Preserves and rendering them.
|
||||||
|
|
||||||
|
For example, to generate configuration for a Syndicate server listener:
|
||||||
|
```dhall
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let Preserves = ./package.dhall
|
||||||
|
|
||||||
|
let Tcp/Type = { address : Text, port : Natural }
|
||||||
|
|
||||||
|
let RelayListener/Type = { transport : Tcp/Type }
|
||||||
|
|
||||||
|
let RequireService/Type = { relayListener : RelayListener/Type }
|
||||||
|
|
||||||
|
let Tcp/toPreserves =
|
||||||
|
λ(tcp : Tcp/Type) →
|
||||||
|
Preserves.record
|
||||||
|
(Preserves.symbol "tcp")
|
||||||
|
[ Preserves.string tcp.address
|
||||||
|
, Preserves.integer (Prelude.Natural.toInteger tcp.port)
|
||||||
|
]
|
||||||
|
|
||||||
|
let RelayListener/toPreserves =
|
||||||
|
λ(relayListener : RelayListener/Type) →
|
||||||
|
Preserves.record
|
||||||
|
(Preserves.symbol "relay-listener")
|
||||||
|
[ Tcp.toPreserves relayListener.transport ]
|
||||||
|
|
||||||
|
let RequireService/toPreserves =
|
||||||
|
λ(requireService : RequireService/Type) →
|
||||||
|
Preserves.record
|
||||||
|
(Preserves.symbol "require-service")
|
||||||
|
[ RelayListener.toPreserves requireService.relayListener ]
|
||||||
|
|
||||||
|
let example = { relayListener.transport = { address = "127.0.0.1", port = 1 } }
|
||||||
|
|
||||||
|
let rendering = Preserves.render (RequireService.toPreserves example)
|
||||||
|
|
||||||
|
let check =
|
||||||
|
assert
|
||||||
|
: rendering ≡ "<require-service <relay-listener <tcp \"127.0.0.1\" 1>>>"
|
||||||
|
|
||||||
|
in rendering
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,10 @@
|
||||||
|
{-|
|
||||||
|
Dhall encoding of an arbitrary Preserves value
|
||||||
|
-}
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let Preserves/Type
|
||||||
|
: Type
|
||||||
|
= ∀(Preserves : Type) → ∀(value : Preserves/function Preserves) → Preserves
|
||||||
|
|
||||||
|
in Preserves/Type
|
|
@ -0,0 +1,15 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves boolean map from a `Bool` value
|
||||||
|
-}
|
||||||
|
let Preserves/Type = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let bool
|
||||||
|
: Bool → Preserves/Type
|
||||||
|
= λ(x : Bool) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.boolean x
|
||||||
|
|
||||||
|
in bool
|
|
@ -0,0 +1,37 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves dictionary value from a Dhall `Map` of `Preserves` values
|
||||||
|
-}
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let List/map = Prelude.List.map
|
||||||
|
|
||||||
|
let Map/Entry = Prelude.Map.Entry
|
||||||
|
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let Preserves/Entry = Map/Entry Preserves Preserves
|
||||||
|
|
||||||
|
let Preserves/Map = List Preserves/Entry
|
||||||
|
|
||||||
|
let map
|
||||||
|
: Preserves/Map → Preserves
|
||||||
|
= λ(x : Preserves/Map) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
let Preserves/Entry = Map/Entry Preserves Preserves
|
||||||
|
|
||||||
|
in λ(value : Preserves/function Preserves) →
|
||||||
|
value.dictionary
|
||||||
|
( List/map
|
||||||
|
Preserves/Entry@1
|
||||||
|
Preserves/Entry
|
||||||
|
( λ(e : Preserves/Entry@1) →
|
||||||
|
{ mapKey = e.mapKey Preserves value
|
||||||
|
, mapValue = e.mapValue Preserves value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|
||||||
|
in map
|
|
@ -0,0 +1,40 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves dictionary value from a Dhall `Map`
|
||||||
|
|
||||||
|
See ./render.dhall for an example.
|
||||||
|
-}
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let List/map = Prelude.List.map
|
||||||
|
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/dictionary = ./dictionary.dhall
|
||||||
|
|
||||||
|
let dictionaryOf
|
||||||
|
: ∀(a : Type) →
|
||||||
|
(a → Preserves) →
|
||||||
|
∀(b : Type) →
|
||||||
|
(b → Preserves) →
|
||||||
|
Prelude.Map.Type a b →
|
||||||
|
Preserves
|
||||||
|
= λ(a : Type) →
|
||||||
|
λ(key : a → Preserves) →
|
||||||
|
λ(b : Type) →
|
||||||
|
λ(value : b → Preserves) →
|
||||||
|
λ(x : Prelude.Map.Type a b) →
|
||||||
|
let ab = Prelude.Map.Entry a b
|
||||||
|
|
||||||
|
let pp = Prelude.Map.Entry Preserves Preserves
|
||||||
|
|
||||||
|
in Preserves/dictionary
|
||||||
|
( List/map
|
||||||
|
ab
|
||||||
|
pp
|
||||||
|
( λ(x : ab) →
|
||||||
|
{ mapKey = key x.mapKey, mapValue = value x.mapValue }
|
||||||
|
)
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|
||||||
|
in dictionaryOf
|
|
@ -0,0 +1,15 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves floating-point value from a `Double` value
|
||||||
|
-}
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let double
|
||||||
|
: Double → Preserves
|
||||||
|
= λ(x : Double) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.double x
|
||||||
|
|
||||||
|
in double
|
|
@ -0,0 +1,15 @@
|
||||||
|
{-|
|
||||||
|
Create an embedded Preserves value.
|
||||||
|
-}
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let embedded
|
||||||
|
: Preserves → Preserves
|
||||||
|
= λ(value : Preserves) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.embedded (value@1 Preserves value)
|
||||||
|
|
||||||
|
in embedded
|
|
@ -0,0 +1,40 @@
|
||||||
|
{-|
|
||||||
|
Translate a `JSON` value to a `Preserves` value
|
||||||
|
-}
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let List/map = Prelude.List.map
|
||||||
|
|
||||||
|
let JSON = Prelude.JSON.Type
|
||||||
|
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let fromJSON
|
||||||
|
: JSON → Preserves
|
||||||
|
= λ(json : JSON) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
json
|
||||||
|
Preserves
|
||||||
|
{ array = value.sequence
|
||||||
|
, bool = λ(x : Bool) → value.symbol (if x then "true" else "false")
|
||||||
|
, double = value.double
|
||||||
|
, integer = value.integer
|
||||||
|
, null = value.symbol "null"
|
||||||
|
, object =
|
||||||
|
let Entry = { mapKey : Text, mapValue : Preserves }
|
||||||
|
|
||||||
|
in λ(m : List Entry) →
|
||||||
|
value.dictionary
|
||||||
|
( List/map
|
||||||
|
Entry
|
||||||
|
{ mapKey : Preserves, mapValue : Preserves }
|
||||||
|
(λ(e : Entry) → e with mapKey = value.string e.mapKey)
|
||||||
|
m
|
||||||
|
)
|
||||||
|
, string = value.string
|
||||||
|
}
|
||||||
|
|
||||||
|
in fromJSON
|
|
@ -0,0 +1,12 @@
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
{ boolean : Bool → Preserves
|
||||||
|
, double : Double → Preserves
|
||||||
|
, integer : Integer → Preserves
|
||||||
|
, string : Text → Preserves
|
||||||
|
, symbol : Text → Preserves
|
||||||
|
, record : Preserves → List Preserves → Preserves
|
||||||
|
, sequence : List Preserves → Preserves
|
||||||
|
, set : List Preserves → Preserves
|
||||||
|
, dictionary : List { mapKey : Preserves, mapValue : Preserves } → Preserves
|
||||||
|
, embedded : Preserves → Preserves
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves integer value from an `Integer` value
|
||||||
|
-}
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let integer
|
||||||
|
: Integer → Preserves
|
||||||
|
= λ(x : Integer) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.integer x
|
||||||
|
|
||||||
|
in integer
|
|
@ -0,0 +1,16 @@
|
||||||
|
{ Type = ./Type.dhall
|
||||||
|
, function = ./function.dhall
|
||||||
|
, boolean = ./boolean.dhall
|
||||||
|
, dictionary = ./dictionary.dhall
|
||||||
|
, dictionaryOf = ./dictionaryOf.dhall
|
||||||
|
, double = ./double.dhall
|
||||||
|
, embedded = ./embedded.dhall
|
||||||
|
, fromJSON = ./fromJSON.dhall
|
||||||
|
, integer = ./integer.dhall
|
||||||
|
, record = ./record.dhall
|
||||||
|
, render = ./render.dhall
|
||||||
|
, sequence = ./sequence.dhall
|
||||||
|
, sequenceOf = ./sequenceOf.dhall
|
||||||
|
, string = ./string.dhall
|
||||||
|
, symbol = ./symbol.dhall
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let List/map = Prelude.List.map
|
||||||
|
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let record =
|
||||||
|
λ(label : Preserves) →
|
||||||
|
λ(fields : List Preserves) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.record
|
||||||
|
(label Preserves value)
|
||||||
|
( List/map
|
||||||
|
Preserves@1
|
||||||
|
Preserves
|
||||||
|
(λ(value : Preserves@1) → value Preserves value@1)
|
||||||
|
fields
|
||||||
|
)
|
||||||
|
|
||||||
|
in record
|
|
@ -0,0 +1,100 @@
|
||||||
|
{-
|
||||||
|
Render a `Preserves` value to a diagnostic `Text` value
|
||||||
|
-}
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let Map/Type = Prelude.Map.Type
|
||||||
|
|
||||||
|
let Text/concatSep = Prelude.Text.concatSep
|
||||||
|
|
||||||
|
let Text/concatMapSep = Prelude.Text.concatMapSep
|
||||||
|
|
||||||
|
let render
|
||||||
|
: Preserves → Text
|
||||||
|
= λ(value : Preserves) →
|
||||||
|
value
|
||||||
|
Text
|
||||||
|
{ boolean = λ(x : Bool) → if x then "#t" else "#f"
|
||||||
|
, double = Double/show
|
||||||
|
, integer = Prelude.JSON.renderInteger
|
||||||
|
, string = Text/show
|
||||||
|
, symbol = λ(sym : Text) → "${sym}"
|
||||||
|
, record =
|
||||||
|
λ(label : Text) →
|
||||||
|
λ(fields : List Text) →
|
||||||
|
"<${label}"
|
||||||
|
++ (if Prelude.List.null Text fields then "" else " ")
|
||||||
|
++ Text/concatSep " " fields
|
||||||
|
++ ">"
|
||||||
|
, sequence = λ(xs : List Text) → "[ " ++ Text/concatSep " " xs ++ " ]"
|
||||||
|
, set = λ(xs : List Text) → "#{" ++ Text/concatSep " " xs ++ " }"
|
||||||
|
, dictionary =
|
||||||
|
λ(m : Map/Type Text Text) →
|
||||||
|
"{ "
|
||||||
|
++ Text/concatMapSep
|
||||||
|
" "
|
||||||
|
{ mapKey : Text, mapValue : Text }
|
||||||
|
( λ(e : { mapKey : Text, mapValue : Text }) →
|
||||||
|
"${e.mapKey}: ${e.mapValue}"
|
||||||
|
)
|
||||||
|
m
|
||||||
|
++ " }"
|
||||||
|
, embedded = λ(value : Text) → "#!${value}"
|
||||||
|
}
|
||||||
|
|
||||||
|
let Preserves/boolean = ./boolean.dhall
|
||||||
|
|
||||||
|
let Preserves/integer = ./integer.dhall
|
||||||
|
|
||||||
|
let Preserves/double = ./double.dhall
|
||||||
|
|
||||||
|
let Preserves/symbol = ./symbol.dhall
|
||||||
|
|
||||||
|
let Preserves/record = ./record.dhall
|
||||||
|
|
||||||
|
let Preserves/sequenceOf = ./sequenceOf.dhall
|
||||||
|
|
||||||
|
let Preserves/dictionaryOf = ./dictionaryOf.dhall
|
||||||
|
|
||||||
|
let Preserves/dictionaryOfSymbols = Preserves/dictionaryOf Text Preserves/symbol
|
||||||
|
|
||||||
|
let Preserves/embedded = ./embedded.dhall
|
||||||
|
|
||||||
|
let example0 =
|
||||||
|
assert
|
||||||
|
: ''
|
||||||
|
${render
|
||||||
|
( Preserves/dictionaryOfSymbols
|
||||||
|
Preserves
|
||||||
|
(λ(x : Preserves) → x)
|
||||||
|
( toMap
|
||||||
|
{ a = Preserves/integer +1
|
||||||
|
, b =
|
||||||
|
Preserves/sequenceOf
|
||||||
|
Integer
|
||||||
|
Preserves/integer
|
||||||
|
[ +2, +3 ]
|
||||||
|
, c =
|
||||||
|
Preserves/dictionaryOfSymbols
|
||||||
|
Double
|
||||||
|
Preserves/double
|
||||||
|
(toMap { d = 1.0, e = -1.0 })
|
||||||
|
, d = Preserves/embedded (Preserves/boolean True)
|
||||||
|
, e =
|
||||||
|
Preserves/record
|
||||||
|
(Preserves/symbol "capture")
|
||||||
|
[ Preserves/record
|
||||||
|
(Preserves/symbol "_")
|
||||||
|
([] : List Preserves)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
''
|
||||||
|
≡ ''
|
||||||
|
{ a: 1 b: [ 2 3 ] c: { d: 1.0 e: -1.0 } d: #!#t e: <capture <_>> }
|
||||||
|
''
|
||||||
|
|
||||||
|
in render
|
|
@ -0,0 +1,27 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves sequence value from a `List` of `Preserve` values
|
||||||
|
|
||||||
|
See ./sequenceOf.dhall for an example.
|
||||||
|
-}
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let List/map = Prelude.List.map
|
||||||
|
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let sequence
|
||||||
|
: List Preserves → Preserves
|
||||||
|
= λ(x : List Preserves) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.sequence
|
||||||
|
( List/map
|
||||||
|
Preserves@1
|
||||||
|
Preserves
|
||||||
|
(λ(value : Preserves@1) → value Preserves value@1)
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|
||||||
|
in sequence
|
|
@ -0,0 +1,21 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves sequence value from a `List` of values and a conversion function
|
||||||
|
|
||||||
|
See ./render.dhall for an example.
|
||||||
|
-}
|
||||||
|
let Prelude = ./Prelude.dhall
|
||||||
|
|
||||||
|
let List/map = Prelude.List.map
|
||||||
|
|
||||||
|
let Preserves = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/sequence = ./sequence.dhall
|
||||||
|
|
||||||
|
let sequenceOf
|
||||||
|
: ∀(a : Type) → (a → Preserves) → List a → Preserves
|
||||||
|
= λ(a : Type) →
|
||||||
|
λ(f : a → Preserves) →
|
||||||
|
λ(xs : List a) →
|
||||||
|
Preserves/sequence (List/map a Preserves f xs)
|
||||||
|
|
||||||
|
in sequenceOf
|
|
@ -0,0 +1,15 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves string from a `Text` value
|
||||||
|
-}
|
||||||
|
let Preserves/Type = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let string
|
||||||
|
: Text → Preserves/Type
|
||||||
|
= λ(x : Text) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.string x
|
||||||
|
|
||||||
|
in string
|
|
@ -0,0 +1,15 @@
|
||||||
|
{-|
|
||||||
|
Create a Preserves symbol from a `Text` value
|
||||||
|
-}
|
||||||
|
let Preserves/Type = ./Type.dhall
|
||||||
|
|
||||||
|
let Preserves/function = ./function.dhall
|
||||||
|
|
||||||
|
let symbol
|
||||||
|
: Text → Preserves/Type
|
||||||
|
= λ(x : Text) →
|
||||||
|
λ(Preserves : Type) →
|
||||||
|
λ(value : Preserves/function Preserves) →
|
||||||
|
value.symbol x
|
||||||
|
|
||||||
|
in symbol
|
Loading…
Reference in New Issue