【问题标题】:Array product given a dynamic number of arguments给定动态数量的参数的数组产品
【发布时间】:2020-04-29 22:02:28
【问题描述】:

我有一个做数组乘积的函数:

arrayProduct(l1,l2,l3) = [[a, b, c] |
    a := l1[_]
    b := l2[_]
    c := l3[_]
]

如果我有如下定义的三个数组:

animals1 = ["hippo", "giraffe"]
animals2 = ["lion", "zebra"]
animals3 = ["deer", "bear"]

那么arrayProduct(animals1, animals2, animals3) 的输出将是:

[["hippo","lion","deer"],["hippo","lion","bear"],["hippo","zebra","deer"],["hippo","zebra","bear"],["giraffe","lion","deer"],["giraffe","lion","bear"],["giraffe","zebra","deer"],["giraffe","zebra","bear"]]

如果我可以保证输入总是列表,我可以创建一个函数来做同样的事情,除了它可以接受动态数量的列表作为输入,而不是仅仅 3 个?

我也在探索是否也可以只使用一个包含其中所有数组的参数来执行此操作,而不是接受多个参数。例如:

[["hippo", "giraffe"], ["lion", "zebra"], ["deer", "bear"], ["ostrich", "flamingo"]]

我们将不胜感激对任何一种方法的解决方案的任何见解。

【问题讨论】:

    标签: open-policy-agent rego


    【解决方案1】:

    没有已知的方法可以在没有内置函数的情况下在 Rego 中计算任意 N 路叉积。

    为什么不能用一种语言编写某些东西可能很难解释,因为它相当于一个证明草图。我们需要证明 Rego 中没有计算 N 路叉积的策略。表达性/复杂性的正式证明尚未制定,因此我们能做的最好的事情就是尝试阐明为什么它可能不可能。

    对于 N 路叉积,归结为 Rego 保证所有输入上的所有策略都终止,并为此限制了嵌套迭代的深度。在您的示例中(使用some 并为清晰起见使用缩进),您有3 个嵌套循环,索引为ijk

    arrayProduct(l1,l2,l3) = [[a, b, c] |
        some i
            a := l1[i]
            some j
                b := l2[j]
                some k
                    c := l3[k]
    ]
    

    要实现 N 路叉积 arrayProduct([l1, l2, ..., ln]),您需要与 N 个嵌套循环等效的东西:

    # NOT valid Rego
    arrayProduct([l1,l2,...,ln]) = [[a, b, ..., n] |
        some i1
            a := l1[i1]
            some i2
                b := l2[i2]
                  ...
                        n := ln[in]
    ]
    

    重要的是,嵌套迭代 N 的程度取决于输入。

    为了保证终止,Rego 限制了策略中嵌套迭代的程度。您只能在策略中出现 some(或更恰当的变量)时嵌套迭代次数。这类似于 SQL 将 JOIN 的数量限制为出现在查询和视图定义中的那些。

    由于N路叉积所需的嵌套度为N,并且N可以大于策略中somes的数量,所以没有办法实现N路叉积。

    作为对比,在任何一个循环 CAN 中迭代的键或值的数量通常取决于输入。这是不能依赖于输入的循环数。

    【讨论】:

      【解决方案2】:

      如果不添加内置函数,则无法在 Rego 中计算列表/数组(或集合或对象)的 n 元乘积。

      在上述场景中,提供动态数量的数组作为函数的输入将等效于传递一个数组数组(就像您在最后提到的那样):

      arrayProduct([arr1, arr2, ..., arrN])
      

      这可行,除了当我们尝试实现arrayProduct 时,我们会卡住,因为 Rego 不允许递归,并且只有在将变量注入引用时才会发生迭代。在您的原始示例中,l1[_] 是对第一个列表中元素的引用,_ 是引用该列表中数组索引的唯一变量。

      OPA/Rego 通过查找满足查询的每个_ 的分配来评估该表达式。 “问题”是输入中的每个列表都需要一个变量。如果数组数组的长度未知,我们将需要无限数量的变量。

      如果你真的需要一个 n 元乘积函数,我建议你现在实现一个 custom built-in function

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-03
        • 1970-01-01
        • 1970-01-01
        • 2020-10-08
        • 2011-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多