haskell - 泛化类参数

标签 haskell typeclass type-families

假设我已经上课了:

class C a b t where
  f :: (a, b) -> (t a, t b)

现在有了这个定义,我可以定义实例:

(a,b) -> (Maybe a, Maybe b)
(a,b) -> ([a], [b])

但不适合(据我所知):

(a,b) -> (a,b)
(a,b) -> ((a, a), (b, b))

我可以像这样更改我的类定义:

type family T a b x

class C a b where
  f :: (a, b) -> (T a b a, T a b b)

这将允许我执行上述操作,但随后我只能声明一个 f对于每个 ab .

基本上我希望能够将类型系列传递为 t在原始定义中,如果已知,则由类型检查器隐式解析。我不想只是成功 f :: (a, b) -> (c, d)因为我想保持 a 的不变性和b对他们做了同样的事情,所以 swap . ff . swap 类型相同。我想我可能需要 injective type families (来自 GHC 8.0)但我不确定。但也许还有另一种方法?

最佳答案

这可能会也可能不会回答您的问题,具体取决于您实际需要做什么。

标准解决方案是使用新类型来定义新实例。例如

newtype Pair a = Pair (a, a)
instance C a b Pair where
   f = ...

但是,这将导致 f 具有类型

f :: (a, b) -> (Pair a, Pair b)

而不是想要的

f :: (a, b) -> ((a, a), (b, b))

后者可以通过无聊的方式恢复:

f' :: (a, b) -> ((a, a), (b, b))
f' p = case f p of (Pair x, Pair y) -> (x, y)

现在,编写诸如 f' 这样的“适配器”函数感觉是多余的:毕竟我们只是删除了一个 newtype 包装器,它不会改变运行时表示。更糟糕的是,这可能效率低下:考虑将 [Pair a] 转换为 [(a, a)]。为此,我们需要映射整个列表,因此我们支付 O(n) 基本上什么都不做。

可以使用 safe coercions 构建有效的替代方案:

import Data.Coerce

f'' :: forall a b. (a, b) -> ((a, a), (b, b))
f'' = coerce (f :: (a, b) -> (Pair a, Pair b))

这允许使用newtype来驱动实例选择,并在它们妨碍时将其删除。

现在,如果您的目标确实是定义没有 newtype 的新实例,那么这并没有多大帮助。相反,如果您想要一种简单的方法来从实例方法中删除 newtype 的包装器,它可以提供帮助。

关于haskell - 泛化类参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32732270/

相关文章:

haskell - Curry编译器zinc无法配置

haskell - 如何隐式导入模块

haskell - 参数类型类名

haskell - 使用类型族避免 MPTC 中的显式类型类参数

haskell - 使用具有 'limited' 约束的约束种类和类型族

haskell - 类型族卡在使用函数依赖的等效类型可以简化的地方

haskell - Haskell 中的闭包是如何工作的?

haskell - 有谁知道(或记得)违反类(Class)法会如何导致 GHC 出现问题?

haskell - 为什么 Haskell 没有比 Eq 更强大的替代方案?

haskell - 在 Haskell 中创建许多类似的新类型/类型类实例