在函数签名中隐藏多参数类型类的类型参数之一

时间:2019-01-23 15:58:04

标签: haskell typeclass

说我有一个多参数类型类:

class B b => C a b | a -> b where
    getB :: a -> (T, b)

然后我想要一个功能:

f :: C a b => a -> c
f = g . getB

哪个使用另一个函数g :: B b => (T, b) -> cgetB,所以需要实例C a b

(免责声明:真正的问题要复杂得多,上述只是简化版本。)

问题是,考虑到功能依赖性C a b | a -> b,我们知道b可以完全由a决定,因此从理论上讲我应该不提bf类型(因为它没有在其他地方使用,而是在实例C a b中使用),但是我没有找到实现此目的的任何方法。

还要注意,由于类B b中存在约束C,我想我不能使用TypeFamilies扩展,因为它的语法对类型约束{{1}毫无用处} 为了生活。

那么,有什么方法可以向函数B b的用户隐藏实现细节(不相关的类型参数b)?

2 个答案:

答案 0 :(得分:7)

使用TypeFamilies,可以将C重写为单参数类,如下所示:

class B (BOf a) => C a where
  type BOf a :: *
  getB :: a -> (T, BOf a)

这为f带来了更好的外观约束:

f :: C a => a -> c

(遗憾的是)没有办法忽略多参数类的参数以获得相似的结果。

答案 1 :(得分:4)

如果打开.then( ({data}) => {,则可以创建一个类型别名,让您像这样跳过RankNTypes

b

如果需要,您甚至可以在第二个参数内包含更多上下文:

type C' a t = forall b. C a b => t
f :: C' a (a -> c)
f = g . getB

这是非常不标准的。您将需要留下解释性的评论……最终,编写该文本的工作可能比在每次使用f' :: C' a ((Num a, Ord c) => a -> c) f' = g . getB 时仅包含b的工作要大。