使用 Dhall 将递归类型编码为 JSON

Encoding recursive types to JSON using Dhall

我想要的输出的简化版本:

{
  "dynamic-name": {
    "type": "type",
    "fields": {
      "inner-dynamic-name": {
        "type": "inner-type",
        "analyzer": "analyzer"
      }
    }
  }
}

这是我编写的 Dhall 代码:

let Field
    : Type
    = ∀(Field : Type) →
      ∀ ( Leaf
        : { mapKey : Text, mapValue : { type : Text, analyzer : Optional Text } } →
            Field
        ) →
      ∀ ( Node
        : { mapKey : Text, mapValue : { type : Text, fields : List Field } } →
            Field
        ) →
        Field

let example
    : Field
    = λ(Field : Type) →
      λ ( Leaf
        : { mapKey : Text, mapValue : { type : Text, analyzer : Optional Text } } →
            Field
        ) →
      λ ( Node
        : { mapKey : Text, mapValue : { type : Text, fields : List Field } } →
            Field
        ) →
        Node
          { mapKey = "dynamic-name"
          , mapValue =
            { type = "type"
            , fields =
              [ Leaf
                  { mapKey = "inner-dynamic-name"
                  , mapValue =
                    { type = "inner-type", analyzer = Some "analyzer" }
                  }
              ]
            }
          }

in  example

但是,当我将 Dhall 配置传递给 dhall-to-json 时,出现以下错误:

Error: Cannot translate to JSON                                            
                                                                                
Explanation: Only primitive values, records, unions, ❰List❱s, and ❰Optional❱    
values can be translated from Dhall to JSON                                     
                                                                                
The following Dhall expression could not be translated to JSON:                 
                                                                                
↳ λ(_ : Type) →
  λ ( _
    : { mapKey : Text, mapValue : { analyzer : Optional Text, type : Text } } →
        _@1
    ) →
  λ(_ : { mapKey : Text, mapValue : { fields : List _@1, type : Text } } → _@2) →
    _
      { mapKey = "dynamic-name"
      , mapValue =
        { fields =
          [ _@1
              { mapKey = "inner-dynamic-name"
              , mapValue = { analyzer = Some "analyzer", type = "inner-type" }
              }
          ]
        , type = "type"
        }
      }

我是 运行 dhall-to-json 的 1.7.6 版。我做错了什么?

(无视:我需要包含更多的单词才能被允许 post 我的问题,但再多的话似乎都是多余的。最后几句话是我是 Hackerman。)

我正在将 https://github.com/dhall-lang/dhall-haskell/issues/2259 的答案复制到此处:

dhall-to-json 无法直接处理自定义递归类型,但它可以处理一种可区分的递归类型,即 Prelude.JSON.Type,因此这样的事情会起作用:

let JSON =
      https://prelude.dhall-lang.org/JSON/package.dhall
        sha256:5f98b7722fd13509ef448b075e02b9ff98312ae7a406cf53ed25012dbc9990ac

let Field
    : Type
    = ∀(Field : Type) →
      ∀ ( Leaf
        : { mapKey : Text
          , mapValue : { type : Text, analyzer : Optional Text }
          } →
            Field
        ) →
      ∀ ( Node
        : { mapKey : Text, mapValue : { type : Text, fields : List Field } } →
            Field
        ) →
        Field

let example
    : Field
    = λ(Field : Type) →
      λ ( Leaf
        : { mapKey : Text
          , mapValue : { type : Text, analyzer : Optional Text }
          } →
            Field
        ) →
      λ ( Node
        : { mapKey : Text, mapValue : { type : Text, fields : List Field } } →
            Field
        ) →
        Node
          { mapKey = "dynamic-name"
          , mapValue =
            { type = "type"
            , fields =
              [ Leaf
                  { mapKey = "inner-dynamic-name"
                  , mapValue =
                    { type = "inner-type", analyzer = Some "analyzer" }
                  }
              ]
            }
          }

let Field/toJSON
    : Field → JSON.Type
    = λ(field : Field) →
        field
          JSON.Type
          ( λ ( args
              : { mapKey : Text
                , mapValue : { type : Text, analyzer : Optional Text }
                }
              ) →
              JSON.object
                [ { mapKey = args.mapKey
                  , mapValue =
                      JSON.object
                        ( toMap
                            { type = JSON.string args.mapValue.type
                            , analyzer =
                                merge
                                  { None = JSON.null, Some = JSON.string }
                                  args.mapValue.analyzer
                            }
                        )
                  }
                ]
          )
          ( λ ( args
              : { mapKey : Text
                , mapValue : { type : Text, fields : List JSON.Type }
                }
              ) →
              JSON.object
                [ { mapKey = args.mapKey
                  , mapValue =
                      JSON.object
                        ( toMap
                            { type = JSON.string args.mapValue.type
                            , fields = JSON.array args.mapValue.fields
                            }
                        )
                  }
                ]
          )

in  Field/toJSON example

… 并且 dhall-to-json 接受:

$ dhall-to-json --file ./example.dhall
{
  "dynamic-name": {
    "fields": [
      {
        "inner-dynamic-name": {
          "analyzer": "analyzer",
          "type": "inner-type"
        }
      }
    ],
    "type": "type"
  }
}