gpt4 book ai didi

haskell - 在 Haskell 中合并自定义数据类型的记录

转载 作者:行者123 更新时间:2023-12-04 00:28:51 25 4
gpt4 key购买 nike

我有一些数据类型

data SomeType = SomeType { a :: Maybe Int
, b :: Maybe String
, c :: Maybe OtherType }

和该类型的两个变量

st1 = SomeType (Just 1) (Just "hello") Nothing
st2 = SomeType Nothing (Just "world") Nothing

我如何合并它们并优先考虑第二个?

merged = SomeType (Just 1) (Just "world") Nothing

这里的a st2Nothing,所以Just 1来自a st1是首选。
对于 b,来自 st2Just "world" 覆盖 st1Just "hello".

我的简单方法是做类似的事情

merge :: SomeType -> SomeType -> SomeType
merge (SomeType a1 b1 c1) (SomeType a2 b2 c2) =
SomeType { a = maybe a1 pure a2
, b = maybe b1 pure b2
, c = maybe c1 pure c2 }

实际类型比这个例子大,c::Maybe OtherType 也需要递归合并。

编辑:另外,我知道以下形式的记录字段更新

st1 { b = Just "world" } 

创建具有更新字段的新记录。不确定这对我的情况是否有帮助。

最佳答案

类型为 SomeType -> SomeType -> SomeType 的函数看起来像是 Semigroup 的候选人,或者至少可以用 Semigroup 实现的东西.有几个选项。

显式合并

如果你保留 SomeType就像在 OP 中一样,您可以写一个明确的 merge像这样的功能:

merge :: SomeType -> SomeType -> SomeType
merge x y = toSomeType $ toTriple x <> toTriple y
where
toTriple (SomeType a b c) = (Last <$> a, Last <$> b, c)
toSomeType (a, b, c) = SomeType (getLast <$> a) (getLast <$> b) c

这会转换每个 SomeType实例到一个三元组(三元组),其中一个 Semigroup如果所有三个元素都具有 Semigroup,则实例存在实例。

不止一个Semigroup Maybe 的实例,但是(来自 GHC 8.4)任何 Maybe aSemigroup (和 Monoid )当 a 时的实例是 Semigroup实例。

Semigroup支持两个值中最后一个的实例是 Last , 所以 toTriple map abMaybe Last值。但是,它不映射 c ,因为在此实现中它假定 OtherType已经是 Semigroup实例(见下文)。

因为生成的三元组本身就是 Semigroup实例,它们可以与 <> 组合运算符(operator)。这为您提供了一个结果三元组,您可以将其转换回 SomeTypetoSomeType .

半群实例

您也可以自己制作类型 Semigroup实例。如果没有歧义,我认为这是最好的。本身,Maybe可以不止一个Semigroup实例,例如偏爱 FirstLast值,分别。

如果您总是想要支持 Last值,但是,您可以在类型中明确说明。这是一种方式 OtherType可以看:

data OtherType =
OtherType { foo :: Maybe (Last Int), bar :: Maybe (Last String) } deriving (Eq, Show)

请注意,这些字段不仅仅是 Maybe值,但显式 Maybe Last值。这产生了明确的 Semigroup实例:

instance Semigroup OtherType where
(OtherType foo1 bar1) <> (OtherType foo2 bar2) =
OtherType (foo1 <> foo2) (bar1 <> bar2)

您也可以对 SomeType 遵循相同的设计原则, 这将使显式 merge功能冗余。

例子

您可以在 GHCi 中尝试上述功能:

*Q54068475> merge st1 st2
SomeType {a = Just 1, b = Just "world", c = Nothing}
*Q54068475> ot1 = OtherType (Just (Last 42)) (Just (Last "foo"))
*Q54068475> ot2 = OtherType (Just (Last 1337)) Nothing
*Q54068475> merge (SomeType (Just 1) (Just "hello") (Just ot1))
(SomeType Nothing (Just "world") (Just ot2))
SomeType {a = Just 1,
b = Just "world",
c = Just (OtherType {foo = Just (Last {getLast = 1337}),
bar = Just (Last {getLast = "foo"})})}

(我在 GHCi session 中添加了一些换行符以使其更具可读性...)

幺半群

这些类型也可以是 Monoid实例:

instance Monoid OtherType where
mempty = OtherType Nothing Nothing

这可能会有用,所以您不妨也考虑添加这些实例...

关于haskell - 在 Haskell 中合并自定义数据类型的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54068475/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com