I’m not exactly certain what I’m asking, but I’m around 6 hours into learning Dhall and I think I have a pretty good handle on things.
I’m attempting to use Dhall to give a convenient DSL-like dialect for defining files, variables, commands and services; however the output of processing the Dhall input should be a graph, nodes and edges.
Ergonomics are important, as this is to be the basis for an internal bring-up-your-dev-env-from-shell-scripts-and-sticky-tape tool, addressing the large number of ancient projects we have which don’t have any kind of orchestration software in sight.
I have some types like this defined, and I really appreciate the syntactic sugar of the record completion operator:
let Command =
{ Type = { name : Text, cmd : Text, deps : List Text }
, default.deps = [] : List Text
}
let Service =
{ Type =
{ name : Text, cmd : Text, ports : List Natural, deps : List Text }
, default = { ports = [] : List Natural, deps = [] : List Text }
}
Ideally, I’d be able to put these in a list, and then fold over them to converd them into a list of records of nodes and edges, e.g:
in [ Service::{
, name = "foo service"
, cmd = "python3 -m http.server"
, ports = [ 3000 ]
}
, Command::{ name = "get the date", cmd = "date" }
]
This should give me a few nodes get-the-date.result.success
, foo_service.ports.3000
, foo_service.running
, and some edges foo_service.ports.3000 -> foo_service.running
.
Of course, I can’t have mixed types in a list, and static record types don’t give me an ability to consume the records and emit new nodes and edges, so I tried to make a union:
let Resource
: Type
= < Service : ServiceDef.Type | Command : CommandDef.Type >
let resources
: List Resource
= [ Resource.Service::{
, name = "foo service"
, cmd = "python3 -m http.server"
, ports = [ 3000 ]
}
, Resource.Command::{ name = "get the date", cmd = "date" }
]
However, no combination of anything in the < .. >
would yield working results, I seemed to be struggling, since the record completion syntax is then breaking with The completion schema must be a record
. It seems that’s because unions and record completion syntax are not compatible? github_com/dhall-lang/dhall-lang/issues/821 (new discourse users can only post 2 links)
I’d like to get my DSL to a point that I can do something like this:
in List/map [ Command::{name = "a"}, Command::{name = "b"}, Service::{name="c"}, Service::{name="d", deps="c/running"} ]
I’d then squint a these docs here a bit, for map/fold to flatten the list of graph nodes into a single Graph Using map and fold to generate a list of strings — Dhall documentation
However all roads lead to needing to have unions with record completion syntax or something akin to that. I think ideally I’d like a simple syntax even, something like
let Node : Type = {}
let Graph : Type = { nodes: List Node, edges: List Edge }
in [
Command {name = "foo"} -- a function, taking an anonymous record, which is merged with defaults, returning a
Command { name = "bar", cmd = "/usr/bin/date" }
]
My apologies for scatterbrain posting on the Discourse board, but I could use a little fundamental guidance on the idiomatic approach to this please!