定义没有数据构造函数的新数据类型

时间:2013-07-26 10:41:10

标签: haskell types

我开始玩Haskell,阅读一些教程和一本官方书籍(lyah)。我觉得自己能够开始我的第一个个人项目。至于我选择的任何新语言,我想实现一个用于线性代数处理的包(围绕矩阵,向量等的操作)。功能还可以,但我对数据类型没有太多的了解。

最初,我有一个看起来像这样的功能:

     add_vect :: (Num a) => [a] -> [a] -> [a]
     add_vect x y = zipWith (+) x y

现在我想给Vector的含义命名([a]),以便vect_add看起来像:

    vect_add :: Vector -> Vector -> Vector
    vect_add x y = zipWith (+) x y

经过多次雄心勃勃的尝试后,我以一个非常简单的定义结束了(受String定义的启发):

    type Vector = [Int] 

这个问题是我失去了我的函数的类型泛型,它现在仅适用于[Int]而不是任何数字类型。

我的问题是:有没有办法在新类型的定义中表达通用性(例如使用类型calsses)。类似于:

    type Vector = (Num a) => [a]

或者是否有其他方法可以保持Vector的通用性?

3 个答案:

答案 0 :(得分:3)

你无法做你想做的事,因为类型检查器无法知道所有三个向量都是相同的类型。否则你可以写这样的代码:

mkVect :: [a] -> Vector   -- You are going to need something with this type.


x1 :: [Int]
x1 = [1,2,3]
x2 :: [Double]
x2 = [1.0,2.0,3.0]

v3 = add_vect (mkVect x1) (mkVect x2)

类型检查器可以阻止这种情况的唯一方法是将Vector的type参数作为add_vect的一部分。

所以你必须写

type Vector a = [a]

通过这种方式,类型检查器可以看到你在做什么。

答案 1 :(得分:3)

嗯...

{-# LANGUAGE RankNTypes     #-}

type Vector = forall a . Num a => [a]

但那并不是你想要的:你最终得到了

addVect :: (forall a.Num a => [a]) -> (forall b.Num b => [b]) -> (forall c.Num c => [c])

无法定义(每个向量可能有不同的数字类型)。

正如保罗约翰逊所说,你可以使用type Vector a = [a](或等同地,type Vector = [])。但我不认为这真的是你想要的:你基本上会得到与现在相同的签名,并且在跨越矢量空间的场上具有参数多态的矢量函数并不是很自然。

正确的解决方案IMO是vector-space package :(简化)

采用的解决方案
class VectorSpace v where
  type Scalar v :: *     -- This is going to be the type of the
                         -- field ("of the components of each vector")

  (^+^) :: v -> v -> v   -- You call this `addVect`
  (*^)  :: (Scalar v) -> v -> v

  ...

然后你可以有例如。

data Vectorℝ2 = Vectorℝ2 !Double !Double

instance VectorSpace Vectorℝ2 where
  type Scalar Vectorℝ2 = Double
  Vectorℝ2 x y ^+^ Vectorℝ2 x' y' = Vectorℝ2 (x+x') (y+y')
  ...

newtype Vectorℝn = Vectorℝn [Double]

instance VectorSpace Vectorℝn where
  type Scalar Vectorℝn = Double
  Vectorℝn xs ^+^ Vectorℝn x's = Vectorℝn $ zipWith (+) xs x's

BTW,zipWith(+)对于变量维向量加法来说并不是一个很好的定义:你会得到例如。

[1,2,3] ^+^ [4,5]  ≡ [5,7]

虽然实际上我希望在矢量意义上[4,5] ≅ [4,5,0],因此[1,2,3] ^+^ [4,5] ≡ [5,7,3] ≆ [5,7]

答案 2 :(得分:0)

一种“正确”的方式是注意您仅使用Vector进行文档编制,因此type Vector a = [a]并不是一件坏事。然后,您必须vect_add :: Vector a -> Vector a -> Vector a必须匹配,甚至vector-space的{​​{1}}。