Search code examples
directed-acyclic-graphsdhall

How can I encode a rule tree of multiple depths in Dhall?


I'm trying to move some error prone YAML into Dhall to make some system configuration simpler. I have a tree that looks like:

composite:
  condition: And
  rules:
    - composite:
        condition: And
        rules:
          - leaf:
              static: true
          - leaf:
              exists: some-property-to-lookup
    - composite:
        condition: Or
        rules:
          - composite:
              condition: And
              rules:
                - leaf:
                    static: true
                - leaf:
                    exists: some-property-to-lookup         

I'm trying to encode this in Dhall and I can't seem to provide the compiler the right information. My latest try looks like:

let Field
    : Type
    = < B : { static : Bool } | S : { exists : Text } >

let Condition
    : Type
    = < And | Or | Not >

let Node
    : Type
    = ∀(Node : Type) →
      ∀(Leaf : { leaf : Field }) →
      ∀(Branch : { composite : { condition : Condition, rules : List Node } }) →
        Node

let example
    : Node
    = ∀(Node : Type) →
      ∀(Leaf : { leaf : Field }) →
      ∀(Branch : { composite : { condition : Condition, rules : List Node } }) →
        Branch
          { composite =
            { condition = Condition.And
            , rules =
              [ Branch
                  { composite =
                    { condition = Condition.And
                    , rules = [ Leaf { leaf = Field.S { exists = "hi" } } ]
                    }
                  }
              , Branch
                  { composite =
                    { condition = Condition.Or
                    , rules = [ Leaf { leaf = Field.S { static = true } } ]
                    }
                  }
              , Branch
                  { composite =
                    { condition = Condition.And
                    , rules =
                      [ Branch
                          { composite =
                            { condition = Condition.And
                            , rules =
                              [ Leaf { leaf = Field.S { exists = "hi" } } ]
                            }
                          }
                      , Branch
                          { composite =
                            { condition = Condition.Or
                            , rules =
                              [ Leaf { leaf = Field.S { static = true } } ]
                            }
                          }
                      ]
                    }
                  }
              ]
            }
          }

in  example

But I get Error: Not a function. Any pointers would be appreciated.

I also tried w/ the Graph module, but I can't seem to convert that to YAML directly.


Solution

  • This works:

    let Field
        : Type
        = < B : { static : Bool } | S : { exists : Text } >
    
    let Condition
        : Type
        = < And | Or | Not >
    
    let Node
        : Type
        = ∀(Node : Type) →
          ∀(Leaf : { leaf : Field } → Node) →
          ∀(Branch : { composite : { condition : Condition, rules : List Node } } → Node) →
            Node
    
    let example
        : Node
        = λ(Node : Type) →
          λ(Leaf : { leaf : Field } → Node) →
          λ(Branch : { composite : { condition : Condition, rules : List Node } } → Node) →
            Branch
              { composite =
                { condition = Condition.And
                , rules =
                  [ Branch
                      { composite =
                        { condition = Condition.And
                        , rules = [ Leaf { leaf = Field.S { exists = "hi" } } ]
                        }
                      }
                  , Branch
                      { composite =
                        { condition = Condition.Or
                        , rules = [ Leaf { leaf = Field.B { static = True } } ]
                        }
                      }
                  , Branch
                      { composite =
                        { condition = Condition.And
                        , rules =
                          [ Branch
                              { composite =
                                { condition = Condition.And
                                , rules =
                                  [ Leaf { leaf = Field.S { exists = "hi" } } ]
                                }
                              }
                          , Branch
                              { composite =
                                { condition = Condition.Or
                                , rules =
                                  [ Leaf { leaf = Field.B { static = True } } ]
                                }
                              }
                          ]
                        }
                      }
                  ]
                }
              }
    
    in  example
    

    Here is the diff between the two:

    12,13c12,13
    <       ∀(Leaf : { leaf : Field }) →
    <       ∀(Branch : { composite : { condition : Condition, rules : List Node } }) →
    ---
    >       ∀(Leaf : { leaf : Field } → Node) →
    >       ∀(Branch : { composite : { condition : Condition, rules : List Node } } → Node) →
    18,20c18,20
    <     = ∀(Node : Type) →
    <       ∀(Leaf : { leaf : Field }) →
    <       ∀(Branch : { composite : { condition : Condition, rules : List Node } }) →
    ---
    >     = λ(Node : Type) →
    >       λ(Leaf : { leaf : Field } → Node) →
    >       λ(Branch : { composite : { condition : Condition, rules : List Node } } → Node) →
    34c34
    <                     , rules = [ Leaf { leaf = Field.S { static = true } } ]
    ---
    >                     , rules = [ Leaf { leaf = Field.B { static = True } } ]
    52c52
    <                               [ Leaf { leaf = Field.S { static = true } } ]
    ---
    >                               [ Leaf { leaf = Field.B { static = True } } ]