💾 Archived View for gemini.spam.works › users › emery › dhall-gemini.gmi captured on 2020-10-31 at 00:48:48. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2020-09-24)
-=-=-=-=-=-=-
The Dhall configuration language
Using functional languages for configuration is an idea that I've invested a lot of time and effort into. Some might argue that these formalisms transform the sensible to the incomprehensible, but in my experience the alternative is to rely on the colloquialisms of experts who really can't explain whats going on anyway. My line of thought is that if documentation can be generated from these descriptions, the fear of getting lost subsides.
What I describe here is a method of generating a collection of Gemini documents from expressions written in the Dhall language. One begins with a description of Gemini text lines as a type, a function for rendering lines to text, and then one is left to supply a function for transforming their configuration type into Gemini lines.
A line of Gemini text can be thougt of as a union type:
let Line = < Text : Text | Link : { url : Text, text : Optional Text } | Preformat : { alt : Optional Text, body : Text } | Heading1 : Text | Heading2 : Text | Heading3 : Text | Item : Text | Quote : Text > in Line
And rendering Gemini is a matter of prepending the correct line prefixes to line content, and concatenating those lines.
The reference implementation of Dhall has a utility for converting records or maps of text to text into directories and folders.
-- This would create the files "foo.txt" and "subdir/foo.txt". { `foo.txt` = "bar", subdir = { `foo.txt` = "bar" } }
-- This alternative would create files "foo.txt" and "bar.txt". [ { mapKey = "foo.txt", mapValue = "…" } , { mapKey = "bar.txt", mapValue = "…" } ]
So a trivial example of generating documents would be passing the following to the `dhall to-directory-tree ` command:
let Doc/Type = { title : Text, body : Text, cite : List Text } let docs = { foo = { title = "On Foo", body = "…", cite = [ "bar.gmi" ] } : Doc/Type , bar = { title = "On Bar", body = "…", cite = [ "foo.gmi" ] } : Doc/Type } let Prelude = https://prelude.dhall-lang.org/v12.0.0/package.dhall sha256:aea6817682359ae1939f3a15926b84ad5763c24a3740103202d2eaaea4d01f4c let Gemini = https://git.sr.ht/~ehmry/dhall-gemini/blob/e6ebfce0d5ebc8b6aa2649d30c75b28aece3fd5c/package.dhall sha256:9ae840932c3323adfcb79213bff29aef873a8a31d87e41f8f8cdcda6fc469956 let docToGemini : Doc/Type → Gemini.Lines = λ(doc : Doc/Type) → [ Gemini.Line.Heading1 doc.title , Gemini.Line.Text "" , Gemini.Line.Text doc.body , Gemini.Line.Text "" , Gemini.Line.Heading2 "Citations" ] # Prelude.List.map Text Gemini.Line (λ(x : Text) → Gemini.Line.Link { url = x, text = None Text }) doc.cite let mapOfDocs : List { mapKey : Text, mapValue : Doc/Type } = toMap docs let mapOfLines : List { mapKey : Text, mapValue : Gemini.Lines } = Prelude.Map.map Text Doc/Type Gemini.Lines docToGemini mapOfDocs let mapOfText : List { mapKey : Text, mapValue : Text } = let Input = { mapKey : Text, mapValue : Gemini.Lines } let Output = { mapKey : Text, mapValue : Text } in Prelude.List.map Input Output ( λ(x : Input) → { mapKey = x.mapKey ++ ".gmi" , mapValue = Gemini.render x.mapValue } ) mapOfLines in mapOfText
Which generates the output:
[ { mapKey = "bar.gmi" , mapValue = '' # On Bar … ## Citations => foo.gmi '' } , { mapKey = "foo.gmi" , mapValue = '' # On Foo … ## Citations => bar.gmi '' } ]
This probably seems a bit absurd, but this is document generation in a total functional language. This is to say that for any value of a type for which a function exists to convert to the Gemini line type decribed above, a Gemini document can be created in bounded time without error.