【问题标题】:Bind type parameter绑定类型参数
【发布时间】:2017-02-02 10:21:55
【问题描述】:

我目前正在使用相当不错的haskell-eigen 库,偶然发现了一个基本但可能是基本的问题(我对实际的haskell 开发很陌生)。

我使用他们的基本矩阵类型

data Matrix a b :: * -> * -> *

其中a 表示haskell,b 表示内部C 类型。这是通过限制实现的

Elem a b

Elem Double CDouble
Elem Float CFloat
-- more for complex types...

虽然不是我想在这里问的问题,但我有点不明白为什么要这样做。由于它显然是一种函数映射,我已经不明白为什么将其表述为等价关系,但无论如何......

我现在想从keys 包中定义(作为一个简单的例子——我有几个)Key 的一个实例。它定义了给定容器的索引键,例如

type instance [] = Int

所以 Key 的实例是在 * -> * 类型上定义的。

但是由于该要求,这将不起作用:

type instance Key Matrix = (Int, Int)

我必须以某种方式使 Matrix 变得亲切 * -> *。所以(来自 c++,我会使用特征类来做到这一点),我尝试了这个:

type family CType a where
    CType Double = CDouble
    CType Float = CFloat

type MatX a = Matrix a (CType a)

换句话说,我尝试使用类型同义词作为实现上述功能类型映射的一种手段。

现在我尝试了以下方法:

type instance Key MatX = (Int, Int)

这给了我“类型同义词‘MatX’应该有 1 个参数,但没有给出任何参数”,我什至尝试了明显错误的方法

type instance Key (MatX a) = (Int, Int)

这给了我“预期的种类 * -> *,但 MatX a 有种类 *”。这对我来说听起来像是“我的编译器期望一个类型超过 0 但 - 作为类型同义词 - 少于 1 个参数”。

所以我的问题是:通常如何在 haskell 中映射类型以解决这种不匹配或以另一种方式摆脱它。

P.S.:我很清楚本征矩阵有索引功能,但是

  1. 我希望它与其他数据类型通用
  2. 我在其他类型实例的其他变体中遇到了这个问题。

编辑:添加了提到的包的参考链接。

【问题讨论】:

  • 老实说,我会摆脱问题的前半部分。您可以使用data Two a b = T 完全重现该行为。另外,请确保包含指向软件包的链接。顺便说一句,stackoverflow.com/questions/2335967/… 与您要查找的内容很接近。
  • Elem 类具有函数依赖关系,因此它表达了函数关系。函数依赖的存在时间比类型族长得多,并且在某些情况下还提供更好的 API(尽管我认为在这种情况下可能不是)。
  • @dfeuer:这很有趣。我有点假设类型上的功能映射太基础了,根本不存在;)。还要注意,在这些情况下,等价关系是完全错误的。没有什么能阻止我拥有多个 (Elem Float Anything) 实例。当然,编译器不会允许歧义,但对我来说,将函数依赖限制为实际函数(在数学意义上)似乎更合理。不会想到在类型级别上,早期的 haskell 更像是 Prolog 而不是 Haskell...
  • 谁说过等价关系?函数依赖意味着你不能拥有多个 Elem Float 实例。第二个参数由第一个参数决定。今天,这仅用于类型检查,但我希望函数依赖最终会像类型族一样实现,以便提供适当的证据。

标签: haskell


【解决方案1】:

你快到了。缺少的一点是必须使用type 同义词饱和 - 也就是说,您必须提供其所有参数。 MatX 本身不是有效类型,只有 MatX a。这样做的原因是 type 同义词只是同义词 - 它们在编译时被扩展,这意味着编译器需要知道所有 type 同义词的参数才能在扩展后获得有效类型。

解决方法是将您的 type 同义词更改为 newtype

newtype MatX a = MatX { getMatX :: Matrix a (CType a) }

newtypes 可以部分应用,因为MatX a 现在是与Matrix a (CType a) 不同的类型。

type instance Key MatX = (Int, Int)

【讨论】:

    【解决方案2】:

    另一个答案显示了将类型同义词转换为可在实例声明中使用的东西的一般情况。但在这种特定情况下,它可以简单得多:因为索引类型对于所有不同的矩阵都是相同的,所以您可以只提供使类型正确所需的参数。因此:

     type instance Key (Matrix a) = (Int, Int)
    

    不需要额外的与 Haskell 和 C 类型相关的类型族,也不需要新的类型。这也将使使用密钥库的 API 变得更加简单,因为您不需要在每次调用周围进行任何新类型的包装和展开。

    【讨论】:

    • 我立即接受了另一个答案,因为我希望在其他时候重用该映射(MatX),因此它非常适合我的用例。但是,您的回答肯定更像是学习一些基础知识,并且在类型参数的顺序正确的情况下应该是首选解决方案。非常感谢分享。
    猜你喜欢
    • 1970-01-01
    • 2015-02-22
    • 1970-01-01
    • 2019-05-12
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多