gpt4 book ai didi

haskell - 从记录中的字段派生实例

转载 作者:行者123 更新时间:2023-12-02 17:15:21 24 4
gpt4 key购买 nike

示例代码:

{-# LANGUAGE NamedFieldPuns #-}

module Sample where

class Sample a where
isA :: a -> Bool
isB :: a -> Bool
isC :: a -> Bool

data X =
X

instance Sample X where
isA = undefined
isB = undefined
isC = undefined

data Wrapper = Wrapper
{ x :: X
, i :: Int
}

instance Sample Wrapper where
isA Wrapper {x} = isA x
isB Wrapper {x} = isB x
isC Wrapper {x} = isC x

这里,我有一些由 X 实现的类,然后是另一个包含 X 的记录 Wrapper

我希望 Wrapper 通过其字段 x 派生 Sample 实例。

我知道我可以通过获取该字段并为每个函数自己调用它来实现此目的,如图所示。

是否有一些标志或方法可以自动或仅执行一次?

这看起来与 DerivingViaGeneralizedNewtypeDeriving 类似,但两者似乎都只针对 newtype 或可强制类型

最佳答案

以下是一些不需要任何扩展的策略,但会牺牲一些前期成本来轻松派生这些类。

请注意,由于 Sample 不是新类型,因此不能保证它只会容纳一个 X,而不是两个、更多或可变数量(也许 X X X 之一?)。因此,正如您将看到的,您的选项必须在结构中明确选择 X,这可能是扩展自动将其派生为不 存在。

导出一个函数而不是多个函数

为了满足Sample,我们确实需要一个X。让我们将其设为类型类:

class HasX t where
getX :: t -> X

class Sample t where
isA :: t -> Bool
isB :: t -> Bool
isC :: t -> Bool
default isA :: HasX t => t -> Bool
isA = isA . getX
default isB :: HasX t => t -> Bool
isB = isB . getX
default isC :: HasX t => t -> Bool
isC = isC . getX

instance HasX Wrapper where
getX = x

instance Sample Wrapper -- no implementation necessary

通过泛型派生

假设我们只想处理以 X 作为第一个字段的记录。为了匹配类型结构,我们可以使用 GHC.Generics 。这里我们添加了一种让 HasX 默认为第一个字段的方法:

class HasX t where
getX :: t -> X
default getX :: (Generic a, HasX (Rep a)) => t -> X
getX = getX . from

instance HasX (M1 D d (M1 C c (M1 S s (Rec0 X) :*: ff))) o where
getX (M1 (M1 ((M1 (K1 x)) :*: _))) = x

HasX 的最后一个实例与具有单个构造函数 (M1 C) 的任何记录 (M1 D) 匹配,该构造函数具有多个(:*:) 字段 (M1 S),第一个字段的类型为 (Rec0) X

(是的,通用实例很笨重。欢迎编辑。)

(要查看 Wrapper 泛型类型的准确表示,请在 GHCi 控制台中检查 Rep Wrapper。)

现在Wrapper的实例可以写成:

data Wrapper = Wrapper
{ x :: X
, i :: Int
}
deriving (Generic, HasX, Sample)

关于haskell - 从记录中的字段派生实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55964963/

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