【问题标题】:Apply type constructor to components of a record type将类型构造函数应用于记录类型的组件
【发布时间】:2016-12-06 22:03:22
【问题描述】:

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

例如,T 为 Maybe,而 R,

data Foo {
  bar :: Int,
  baz :: Bool
}

机制应该给予,

data Foo {
  bar :: Maybe Int,
  baz :: Maybe Bool
}

或者可能,

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

Opt 后缀被指定为参数。

【问题讨论】:

  • 你能用data Foo f { bar :: f Int, baz :: f Bool },然后type FooOpt = Foo Maybe这样简单的方法来解决这个问题吗?还是需要不同类型的类型安全?
  • 不,我不能触摸原始类型。
  • 你确定你不能概括原始类型,所以像 Alexis 建议的那样使用几乎同构的类型吗?否则,我想 Template Haskell 是你唯一的选择,但我想知道你为什么真的需要这个。
  • 你真的需要一个正确的data 声明(在这种情况下没有办法绕过 TH),还是你只需要 某种同构的类型到修改后的@987654330 @?在这种情况下,单独使用泛型的解决方案可能是可能的(这当然需要 RGeneric 实例,但这不应该成为障碍)。
  • generics-sop 可以做类似的事情stackoverflow.com/questions/39020787/…

标签: haskell template-haskell


【解决方案1】:

你可以用另一种类型(通常是仿函数)参数化你的类型并做

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

他们使用Foo IdentityFoo Maybe。这个问题是Foo Identity 没有给你{bar :: Int, baz :: Bool} 而是{bar :: Identity Int, baz :: Identity Bool}。它在语义上是等效的,但在实践中很痛苦,因为您必须从 Identity 中解开所有字段。

然而,优点是您可以编写在f 上通用的方法,并且适用于Foo IdentityFoo Maybe。您可以使用类型族摆脱Identity

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}

【讨论】:

  • 不错。我不知道 EraseIdentity
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
  • 2020-08-06
相关资源
最近更新 更多