在 Dhall 中反转数据的 N-N 映射
Reverse a N-N mapping of data in Dhall
给出的是应用程序和容器的配置,一个应用程序可以有多个容器,一个容器可以有多个应用程序。我希望能够以两种方式输出它们
- 每个应用列出容器
- 每个容器列出应用程序
数据格式很简单,但我似乎无法找到一种方法来获得这两种表示而不重复关系。
从具有应用程序的容器启动时的示例数据
let app1 = { name = "app1" }
let app2 = { name = "app2" }
let containers = [
{ name = "container1", apps = [ app1 ] },
{ name = "container2", apps = [ app1, app2 ] }
]
{- I can easily transform this data to the following -}
[
{ app = "app1", container = "container1" },
{ app = "app1", container = "container2" },
{ app = "app2", container = "container2" }
]
{- But I cannot seem to get it into the requested format -}
[
"app1" = [ "container1", "container2" ]
"app2" = [ "container2" ]
]
我认为使用标识符作为 Text
是行不通的,因为无法使用相同的标识符合并关联列表或类似的东西。
使用记录我可以合并这样的东西{a1 = {c1 = True}} /\ {a1 = {c2 = True}} /\ {a2 = {c2 = True}}
。这将是 {a1 = {c1 = True, c2 = True}, a2 = {c2 = True}}
。
但是我一开始就无法进入这个状态,因为我无法 'reverse' 记录。
我不关心我需要如何构造配置,只要我不需要重复关系两次即可。
是的,不可能完全按照您的要求执行,因为该语言不允许 Text
比较
我能想到的最接近的解决方案是这样的:
let Map = https://prelude.dhall-lang.org/v21.1.0/Map/Type.dhall
let List/concatMap = https://prelude.dhall-lang.org/v21.1.0/List/concatMap.dhall
let List/map = https://prelude.dhall-lang.org/v21.1.0/List/map.dhall
let startingMapping
: Map Text (Map Text {})
= toMap
{ container1 = toMap { app1 = {=} }
, container2 = toMap { app1 = {=}, app2 = {=} }
}
let desiredMapping
: Map Text (Map Text {})
= toMap
{ app1 = toMap { container1 = {=}, container2 = {=} }
, app2 = toMap { container2 = {=} }
}
let transpose
: ∀(a : Type) → Map Text (Map Text a) → Map Text (Map Text a)
= λ(a : Type) →
List/concatMap
{ mapKey : Text, mapValue : Map Text a }
{ mapKey : Text, mapValue : Map Text a }
( λ(x : { mapKey : Text, mapValue : Map Text a }) →
List/map
{ mapKey : Text, mapValue : a }
{ mapKey : Text, mapValue : Map Text a }
( λ(y : { mapKey : Text, mapValue : a }) →
{ mapKey = y.mapKey
, mapValue =
[ { mapKey = x.mapKey, mapValue = y.mapValue } ]
}
)
x.mapValue
)
in assert : transpose {} startingMapping ≡ desiredMapping
断言失败,但出现以下错误消息:
Error: Assertion failed
[ - { mapKey = "app1"
, mapValue = [ { mapKey = "container1", mapValue = {=} } ]
}
, - { mapKey = "app1"
, mapValue = [ { mapKey = "container2", mapValue = {=} } ]
}
, + { mapKey = "app1"
, mapValue =
[ { mapKey = "container1", mapValue = {=} }
, { mapKey = "container2", mapValue = {=} }
]
}
, …
]
41│ assert : transpose {} startingMapping ≡ desiredMapping
... 因为结果没有像您请求的那样合并两个重复的 app1
键。
给出的是应用程序和容器的配置,一个应用程序可以有多个容器,一个容器可以有多个应用程序。我希望能够以两种方式输出它们
- 每个应用列出容器
- 每个容器列出应用程序
数据格式很简单,但我似乎无法找到一种方法来获得这两种表示而不重复关系。
从具有应用程序的容器启动时的示例数据
let app1 = { name = "app1" }
let app2 = { name = "app2" }
let containers = [
{ name = "container1", apps = [ app1 ] },
{ name = "container2", apps = [ app1, app2 ] }
]
{- I can easily transform this data to the following -}
[
{ app = "app1", container = "container1" },
{ app = "app1", container = "container2" },
{ app = "app2", container = "container2" }
]
{- But I cannot seem to get it into the requested format -}
[
"app1" = [ "container1", "container2" ]
"app2" = [ "container2" ]
]
我认为使用标识符作为 Text
是行不通的,因为无法使用相同的标识符合并关联列表或类似的东西。
使用记录我可以合并这样的东西{a1 = {c1 = True}} /\ {a1 = {c2 = True}} /\ {a2 = {c2 = True}}
。这将是 {a1 = {c1 = True, c2 = True}, a2 = {c2 = True}}
。
但是我一开始就无法进入这个状态,因为我无法 'reverse' 记录。
我不关心我需要如何构造配置,只要我不需要重复关系两次即可。
是的,不可能完全按照您的要求执行,因为该语言不允许 Text
比较
我能想到的最接近的解决方案是这样的:
let Map = https://prelude.dhall-lang.org/v21.1.0/Map/Type.dhall
let List/concatMap = https://prelude.dhall-lang.org/v21.1.0/List/concatMap.dhall
let List/map = https://prelude.dhall-lang.org/v21.1.0/List/map.dhall
let startingMapping
: Map Text (Map Text {})
= toMap
{ container1 = toMap { app1 = {=} }
, container2 = toMap { app1 = {=}, app2 = {=} }
}
let desiredMapping
: Map Text (Map Text {})
= toMap
{ app1 = toMap { container1 = {=}, container2 = {=} }
, app2 = toMap { container2 = {=} }
}
let transpose
: ∀(a : Type) → Map Text (Map Text a) → Map Text (Map Text a)
= λ(a : Type) →
List/concatMap
{ mapKey : Text, mapValue : Map Text a }
{ mapKey : Text, mapValue : Map Text a }
( λ(x : { mapKey : Text, mapValue : Map Text a }) →
List/map
{ mapKey : Text, mapValue : a }
{ mapKey : Text, mapValue : Map Text a }
( λ(y : { mapKey : Text, mapValue : a }) →
{ mapKey = y.mapKey
, mapValue =
[ { mapKey = x.mapKey, mapValue = y.mapValue } ]
}
)
x.mapValue
)
in assert : transpose {} startingMapping ≡ desiredMapping
断言失败,但出现以下错误消息:
Error: Assertion failed
[ - { mapKey = "app1"
, mapValue = [ { mapKey = "container1", mapValue = {=} } ]
}
, - { mapKey = "app1"
, mapValue = [ { mapKey = "container2", mapValue = {=} } ]
}
, + { mapKey = "app1"
, mapValue =
[ { mapKey = "container1", mapValue = {=} }
, { mapKey = "container2", mapValue = {=} }
]
}
, …
]
41│ assert : transpose {} startingMapping ≡ desiredMapping
... 因为结果没有像您请求的那样合并两个重复的 app1
键。