Dhall as a template engine - Dhall

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Mats Rauhala

Tell me why this isn't a good idea. I'm thinking that dhall might be really suitable as a templating language ala mustache, but with types:

let Person =
  { name : Text
  , age : Natural
  }
let Message =
  { recipient : Person
  , sender : Person
  , content : Text
  }

let Text/concatMapSep = https://prelude.dhall-lang.org/Text/concatMapSep sha256:c272aca80a607bc5963d1fcb38819e7e0d3e72ac4d02b1183b1afb6a91340840

let renderMessage : Message -> Text =
  \(message : Message) ->
  ''
  Message from ${message.sender.name}
  Sent to ${message.recipient.name}

  ${message.content}
  ''

let fun : List Message -> Text =
  Text/concatMapSep "----------------------" Message renderMessage
in

fun
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}
module Main where

import Dhall.Deriving
import GHC.Generics (Generic)
import Dhall (FromDhall(..), ToDhall(..), inputFile, auto)

import Data.Text (Text)
import qualified Data.Text.IO as T

import Numeric.Natural

data Person
  = Person { personName :: !Text
           , personAge :: !Natural
           }
  deriving (Show, Generic)
  deriving (FromDhall, ToDhall)
    via Codec (Field (CamelCase <<< DropPrefix "person")) Person

data Message
  = Message { messageRecipient :: !Person
            , messageSender :: !Person
            , messageContent :: !Text
            }
  deriving (Show, Generic)
  deriving (FromDhall, ToDhall)
    via Codec (Field (CamelCase <<< DropPrefix "message")) Message

main :: IO ()
main = do
  renderMessage <- inputFile auto "template.dhall"
  let recipient = Person "foo" 3
      sender = Person "bar" 3
  T.putStrLn . renderMessage $ [Message recipient sender "content of the message"]
Mats Rauhala

This is using the a -> b instance of FromDhall to "compile" the templates, so you end up having a normal [Message] -> Text as your template function in haskell, so there is no round tripping to dhall.

tristanC

I think that's a great idea, as long as you can define the input using dhall types. I have been doing such things using the cli, e:g: dhall text <<< "./template.dhall $(yaml-to-dhall input.yaml)"

Mats Rauhala

One of the downsides I can think of is the lack of date types and their formatters. You end up normalizing the records to text and whatever else primitives