Haskell 将类型构造函数应用于记录类型的组件

Haskell 将类型构造函数应用于记录类型的组件,haskell,template-haskell,Haskell,Template Haskell,给定一个固定类型构造函数T和一个记录类型R,是否有一种机制来为其组件为R的组件但T应用于该类型的记录类型创建声明 例如,T是可能是,而R data Foo { bar :: Int, baz :: Bool } 机制应该给予, data Foo { bar :: Maybe Int, baz :: Maybe Bool } 或者可能 data FooOpt { barOpt :: Maybe Int, bazOpt :: Maybe Bool } 其中,Opt后缀指

给定一个固定类型构造函数T和一个记录类型R,是否有一种机制来为其组件为R的组件但T应用于该类型的记录类型创建声明

例如,T是
可能是
,而R

data Foo {
  bar :: Int,
  baz :: Bool
}
机制应该给予,

data Foo {
  bar :: Maybe Int,
  baz :: Maybe Bool
}
或者可能

data FooOpt {
  barOpt :: Maybe Int,
  bazOpt :: Maybe Bool
}

其中,
Opt
后缀指定为参数。

您可以使用另一个类型(通常是函子)参数化您的类型,并执行以下操作

他们使用
Foo身份
Foo可能
。这方面的问题是
Foo Identity
不会给您
{bar::Int,baz::Bool}
,而是
{bar::Identity Int,baz::Identity Bool}
。它在语义上是等价的,但在实践中是一种痛苦,因为您必须从标识中展开所有字段

然而,其优点是,您可以编写在
f
上通用的方法,并同时适用于
Foo-Identity
Foo-Maybe
。您可以通过使用类型族来摆脱
标识

type family EraseIdentity f a where
     EraseIdentity Identity a = a
     EraseIdentity f a = f a

 data Foo f = Foo {
      bar :: EraseIdentity f Int
      baz :: EraseIdentity f Bool
 }

类型族是类型上的函数,您在这里要说的是,将
Identity a
转换为
a
。现在
Foo-Identity
是一个
{bar::Int,baz::Bool}

你能用像
数据Foo-f{bar::Int,baz::f-Bool}
这样简单的方法来解决这个问题吗?或者你需要单独类型的类型安全性吗?不,我不能接触原始类型。你确定不能概括原始类型,所以按照Alexis的建议使用近似同构的类型吗?否则,我想模板Haskell是你唯一的选择,但我想知道你为什么真的需要它。你真的需要一个合适的
数据
声明(在这种情况下,没有办法绕过TH),还是只需要一些与修改后的
R
同构的类型?在这种情况下,仅使用泛型的解决方案是可能的(这当然需要
R
Generic
实例,但这不应该是一个障碍)。我不知道你的身份
type family EraseIdentity f a where
     EraseIdentity Identity a = a
     EraseIdentity f a = f a

 data Foo f = Foo {
      bar :: EraseIdentity f Int
      baz :: EraseIdentity f Bool
 }