2

我正在 Dhall 中创建 AWS Step Function 定义。但是,我不知道如何创建他们用于Choice状态的通用结构,例如下面的示例:

{
    "Not": {
        "Variable": "$.type",
        "StringEquals": "Private"
    },
    "Next": "Public"
}

使用andNot非常简单。如果我定义一个基本比较:mapKeymapValue

{ Type =
    { Variable : Text
    , StringEquals : Optional Text
    }
, default = 
    { Variable = "foo" 
    , StringEquals = None Text
    }
}

和类型:

let ComparisonType = < And | Or | Not >

Text并添加一个辅助函数来呈现类型mapKey

let renderComparisonType = \(comparisonType : ComparisonType )
    -> merge
    { And = "And"
    , Or = "Or"
    , Not = "Not"
    }
    comparisonType

然后我可以在函数中使用它们来中途生成记录:

let renderRuleComparisons = 
  \( comparisonType : ComparisonType ) ->
  \( comparisons : List ComparisonOperator.Type ) ->
    let keyName = renderComparisonType comparisonType
    let compare = [ { mapKey = keyName, mapValue = comparisons } ]
    in compare

如果我使用以下方法运行它:

let rando = ComparisonOperator::{ Variable = "$.name", StringEquals = Some "Cow" }
let comparisons = renderRuleComparisons ComparisonType.Not [ rando ]
in comparisons

使用dhall-to-json,她将输出第一部分:

{
    "Not": {
        "Variable": "$.name",
        "StringEquals": "Cow"
    }
}

...但我一直在努力将其与"Next": "Sup". 我已经使用了所有的记录合并,如/\,//等,它不断给我各种类型的错误,我还没有真正理解。

4

1 回答 1

1

首先,我将包含一种不进行类型检查的方法作为激发解决方案的起点:

let rando = ComparisonOperator::{ Variable = "$.name", StringEquals = Some "Cow" }

let comparisons = renderRuleComparisons ComparisonType.Not [ rando ]

in  comparisons # toMap { Next = "Public" }

toMap是将记录转换为键值列表的关键字,#是列表连接运算符。Dhall CheatSheet有几个如何使用它们的示例。

上述解决方案不起作用,因为#无法合并具有不同元素类型的列表。运算符的左侧#有这种类型:

comparisons : List { mapKey : Text, mapValue : Comparison.Type }

...而运算符的右侧#具有这种类型:

toMap { Next = "Public" } : List { mapKey : Text, mapValue : Text }

...因此,由于字段List的类型不同,这两个 s 无法按原样合并。mapValue

有两种方法可以解决这个问题:

  • 方法一:只要有类型冲突就使用联合
  • 方法 2:使用可以保存任意值的弱类型 JSON 表示

方法 1 是这个特定示例的更简单的解决方案,方法 2 是更通用的解决方案,可以处理非常奇怪的 JSON 模式。

对于方法 1,dhall-to-json将在转换为 JSON 时自动去除非空联合构造函数(留下它们包装的值)。这意味着您可以转换#运算符的两个参数以就这种常见类型达成一致:

List { mapKey : Text, mapValue : < State : Text | Comparison : Comparison.Type > }

...然后您应该能够连接两个键值对列表并dhall-to-json正确呈现它们。

还有第二种处理弱类型 JSON 模式的解决方案,您可以在此处了解更多信息:

基本思想是所有 JSON/YAML 集成都识别并支持弱类型 JSON 表示,该表示可以保存任意 JSON 数据,包括具有不同形状键的字典(如您的示例中)。您甚至不需要将整个表达式转换为这种弱类型表示;您只需将此表示用于遇到架构问题的配置子集。

这对您的示例意味着什么,您可以将#运算符的两个参数都更改为具有这种类型:

let Prelude = https://prelude.dhall-lang.org/v12.0.0/package.dhall

in  List { mapKey : Text, mapValue : Prelude.JSON.Type }

文档Prelude.JSON.Type还包含有关如何使用此类型的更多详细信息。

于 2020-02-10T06:59:19.517 回答