将不同模式与联合值相关联的 dhall 惯用方法是什么?

What is the dhall idiomatic way to associate different schemas to union values?

我正在尝试使用 Dhall 类型表示 Zuul-CI 项目的管道系统: 管道可以使用具有不同触发事件的不同连接。

我想提供一个默认管道,以这种方式为每种类型的连接设置正确的触发事件:

  ⊢ RenderPipeline CheckPipeline::{ connections = [ ConnectionTypes.GitHub ] }

  - pipeline:
    name: check
    trigger:
      github:
        action: open
        event: pull-request

  ⊢ RenderPipeline CheckPipeline::{ connections = [ ConnectionTypes.Gerrit ] }

  - pipeline:
    name: check
    trigger:
      gerrit:
        event: patchset-created

  ⊢ RenderPipeline CheckPipeline::{ connections = [ ConnectionTypes.Gerrit, ConnectionTypes.GitHub ] }

  - pipeline:
      name: check
      trigger:
        gerrit:
          event: patchset-created
        github:
          action: open
          event: pull-request

我不得不为 ConnectionTrigger 使用 Union,因为合并函数要求值是单一类型。

有没有办法以某种方式将 GerritTrigger 与 ConnectionTypes.Gerrit 相关联并避免在 CheckPipeline 定义中键入事件类型(例如删除 ConnectionTrigger.Gerrit 注释)?

let Prelude =
      https://raw.githubusercontent.com/dhall-lang/dhall-lang/v11.1.0/Prelude/package.dhall sha256:99462c205117931c0919f155a6046aec140c70fb8876d208c7c77027ab19c2fa

let ConnectionTypes
    : Type
    = < Gerrit | GitHub >

let GerritTrigger
    : Type
    = { event : Text }

let GitHubTrigger
    : Type
    = { event : Text, action : Text }

let ConnectionTrigger
    : Type
    = < Gerrit : GerritTrigger | GitHub : GitHubTrigger >

let Pipeline
    : Type
    = { name : Text
      , trigger : { Gerrit : ConnectionTrigger, GitHub : ConnectionTrigger }
      , connections : List ConnectionTypes
      }

let CheckPipeline =
      { Type = Pipeline
      , default =
          { name = "check"
          , trigger =
              -- "Here, can this be improved so that Gerrit is not mentioned twice?"
              { Gerrit = ConnectionTrigger.Gerrit { event = "patchset-created" }
              , GitHub =
                  ConnectionTrigger.GitHub
                    { event = "pull-request", action = "open" }
              }
          }
      }

let PipelineRenderTrigger
    : Type
    = { mapKey : Text, mapValue : ConnectionTrigger }

let RenderPipeline =
        λ(pipeline : Pipeline)
      → [ { pipeline =
              { name = pipeline.name
              , trigger =
                  Prelude.List.map
                    ConnectionTypes
                    PipelineRenderTrigger
                    (   λ(connection : ConnectionTypes)
                      → { mapKey =
                            merge
                              { Gerrit = "gerrit", GitHub = "github" }
                              connection
                        , mapValue = merge pipeline.trigger connection
                        }
                    )
                    pipeline.connections
              }
          }
        ]

in  RenderPipeline CheckPipeline::{ connections = [ ConnectionTypes.GitHub ] }

提前致谢:)

是的,您可以通过转换 triggers 字段,然后将其作为处理程序记录传递给 merge 来实现。这样用户就不必自己包装触发器; RenderPipeline 函数为他们做这件事:

let Prelude =
      https://raw.githubusercontent.com/dhall-lang/dhall-lang/v11.1.0/Prelude/package.dhall sha256:99462c205117931c0919f155a6046aec140c70fb8876d208c7c77027ab19c2fa

let ConnectionTypes
    : Type
    = < Gerrit | GitHub >

let GerritTrigger
    : Type
    = { event : Text }

let GitHubTrigger
    : Type
    = { event : Text, action : Text }

let ConnectionTrigger
    : Type
    = < Gerrit : GerritTrigger | GitHub : GitHubTrigger >

let Pipeline
    : Type
    = { name : Text
      , trigger : { Gerrit : GerritTrigger, GitHub : GitHubTrigger }
      , connections : List ConnectionTypes
      }

let CheckPipeline =
      { Type = Pipeline
      , default =
          { name = "check"
          , trigger =
              { Gerrit = { event = "patchset-created" }
              , GitHub = { event = "pull-request", action = "open" }
              }
          }
      }

let PipelineRenderTrigger
    : Type
    = { mapKey : Text, mapValue : ConnectionTrigger }

let RenderPipeline =
        λ ( pipeline
          : Pipeline
          )
      → [ { pipeline =
              { name =
                  pipeline.name
              , trigger =
                  Prelude.List.map
                    ConnectionTypes
                    PipelineRenderTrigger
                    (   λ ( connection
                          : ConnectionTypes
                          )
                      → { mapKey =
                            merge
                              { Gerrit = "gerrit", GitHub = "github" }
                              connection
                        , mapValue =
                            let {- This is the key bit!

                                   We modify the handlers before passing them to
                                   `merge` so that the user does not have to
                                -}
                                trigger =
                                  { Gerrit =
                                      ConnectionTrigger.Gerrit
                                        pipeline.trigger.Gerrit
                                  , GitHub =
                                      ConnectionTrigger.GitHub
                                        pipeline.trigger.GitHub
                                  }

                            in  merge trigger connection
                        }
                    )
                    pipeline.connections
              }
          }
        ]

in  RenderPipeline CheckPipeline::{ connections = [ ConnectionTypes.GitHub ] }