2017-02-01 49 views
1

我目前正在使用相当不错的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) 

我必须以某种方式使基体是一种*的 - > *。所以(从C++来我想去使用traits类做到这一点),我尝试这样做:

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板’应该有一个参数,但是已经给定无”,我甚至尝试了明显错误

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

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

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

PS:我清楚地知道,特征矩阵具有索引功能,但

  1. 我想这是一个普遍的与其他数据类型
  2. 我在其他其他变种这个问题类型实例。

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

+0

说实话,我会摆脱问题的前半部分。你可以用'data Two a b = T'完全重现那个行为。另外,请确保包含指向软件包的链接。顺便说一下,https://stackoverflow.com/questions/2335967/manipulating-the-order-of-arguments-to-type-constructors接近你要找的东西。 – Zeta

+0

Elem类有一个函数依赖关系,所以它表达了一个函数关系。功能依赖比类型系列要长很多,并且在某些情况下也提供了更好的API(尽管我认为在这种情况下可能不是这样)。 – dfeuer

+0

@dfeuer:这很有趣。我认为类型上的功能映射太基本了,根本就不存在;)。还要注意,在这些情况下等价关系是错误的。没有什么能阻止我有多个(Elem Float Anything)实例。当然,编译器不允许含糊不清,但对于我来说,将函数依赖限制在实际函数(从数学意义上说)似乎更合理。不会认为在类型层次上,早期的haskell更像是一个Prolog而不是Haskell ... –

回答

5

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

修复方法是将您的type的同义词更改为newtype

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

newtype小号可以部分地施加,因为MatX a现在是一个不同类型Matrix a (CType a)

type instance Key MatX = (Int, Int) 
4

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

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

没有额外的类型家族需要Haskell和C类型,不需要新的类型。这也将使得使用密钥的库API更加简单,因为在每次调用时都不需要进行任何新类型的打包和解包。

+0

我立即接受了其他答案,因为我期望在其他某个点重用该映射(MatX),因此它非常适合我的用例。然而,你的答案肯定更像是学习一些基本的东西,并且应该是类型参数顺序正确的情况下的首选解决方案。所以感谢分享。 –