是否可以使用 Haskell 中的列表填充记录?

Is it possible to populate a record using a list in Haskell?

如果我有这样的记录:

data EdgeSet = EdgeSet {
    top :: Int,
    right :: Int,
    bottom :: Int,
    left :: Int,
} deriving (Show)

是否可以通过匹配类型列表填充属性?

我正在追逐以下内容:

...
where
    edgeList = [1, 2, 3, 4]
    edgeSet = EdgeSet {edgeList}

如果没有,有什么想法可以让我比现在更简洁一点吗?

EdgeSet {top=edgeList !! 0, left=edgeList !! 1, bottom=edgeList !! 2, right=edgeList !! 3}

我想不出比

更短的东西
where
    -- given
    edgeList = [1, 2, 3, 4]
    -- split into components and call the constructor
    [x1,x2,x3,x4] = edgeList
    edgeSet = EdgeSet x1 x2 x3 x4

也许库中有一些 Generic helper,但我不知道有这样的东西。

请注意,如果 edgeList 不是四个元素长,上面的代码将在运行时使您的程序崩溃。如果列表来源不受信任,您可能想要验证列表,例如使用 case of 并更优雅地处理意外长度。

如果您确信您使用的列表始终恰好有 4 个元素,那么与 Haskell 一样,模式匹配是最好、最易读的选项:

edgeSet = let [a, b, c, d] = edgeList in EdgeSet a b c d

如果您需要重用它,您可以轻松地将其提取到一个函数中。

请注意,正如我所暗示的,如果给定一个长度小于四的列表,这将崩溃 - 但你给出的解决方案也会崩溃。 (实际上,您的列表将适用于长度为 5 或更长的列表,而我的则不会 - 但如果您愿意,您可以轻松调整模式以应对这种情况。)

我不知道 Haskell 提供了更好的语法来执行此操作。我会建议重新考虑您是否需要一个列表 - 将数据直接输入 EdgeSet 构造函数而不是通过列表可能会更容易和更惯用。这显然在一定程度上取决于您最初是如何获取数据的。

另请注意,如果您确定只有 4 个元素,则 4 元组的类型比列表安全得多,因为编译器随后会确保您拥有正确的数字。

可能不是您要找的东西,但总是可以按照以下方式做一些事情:

module EdgeSet where

data EdgeSet = EdgeSet {
  top :: Int,
  right :: Int,
  bottom :: Int,
  left :: Int
} deriving (Show)

class ListToMyClass a where
  fromListToClass :: [Int] -> a

instance ListToMyClass EdgeSet where
  fromListToClass [a,b,c,d] = EdgeSet a b c d

你必须知道列表的长度是 4。