如何在 Haskell 中对我的自定义数据类型使用预定义函数(例如 ==、tail)?

How to use predefined function (e.g. ==, tail) on my custom data type in Haskell?

我是 haskell 的新手,我在网上阅读的内容对我没有任何帮助。我的任务是实现一个类型类 VEC,它有一个函数 factor,它计算两个整数的乘法或执行两个矩阵的点积,如果用户输入的不是两个数字,而是两个向量类型的整数列表。我的代码如下所示:

data Vector = VECTOR [Int] deriving (Show, Eq)
class VEC a where
    factor :: a -> a -> a
instance VEC Int where
    factor a b = a*b
instance VEC Vector where
    factor xs [] = 0
    factor xs ys = (head xs) * (head ys) + factor (tail xs) (tail ys)

我假设 Vectors 是 [Int] 类型,但现在我不太确定,因为我在尝试使用 Hugs 编译代码时收到以下错误消息:

Hugs> :l kdp  
ERROR file:kdp.hs:7 - Type error in instance member binding  
*** Term           : []  
*** Type           : [a]  
*** Does not match : Vector

所以我的问题是:第一行到底是什么意思?它是与作业一起给出的,我见过许多类似的数据类型定义,但 none 具有这种特定模式。然后如何解决无法使用预定义函数(例如 tail 或在上述错误情况下将整数列表与我的自定义数据类型进行比较的问题?我的猜测是我必须自己定义操作,但我不知道该怎么做。

当你为 class 类的

编写实例时
class C a where
  method :: a -> a

您将所有参数外观 (a) 替换为您为其编写实例的类型。例如你的情况:

{-# LANGUAGE InstanceSigs #-}
instance VEC Vector where
    factor :: Vector -> Vector -> Vector
    factor _ _ = undefined

因此您不能将 Vector 类型的参数与模式 [] 匹配,也不能在其上使用 headtail 函数,因为它们正在处理列表。但是,您的 Vector 由列表组成,因此您可以简单地解压它:

instance VEC Vector where
    factor _ (Vector []) = Vector [0] -- you need to return Vector as well
    factor (Vector xs) (Vector ys) =
      let Vector [x] = factor (Vector $ tail xs) (Vector $ tail ys)
      in Vector [(head xs) * (head ys) + x]

这是非常丑陋和不完整的,你可以使用一些内置的 Data.List 机制让它更性感:

instance VEC Vector where
  factor (Vector xs) (Vector ys) =
    Vector [sum (zipWith (*) xs ys)]

当您使用 deriving (Show, Eq) 时,== 运算符应该可以正常工作。

您可以概括您的类型 class 以采用 两个 类型变量,以适应​​整数乘法和向量点积这两种不同的运算。不过,这需要两个特定于 GHC 的扩展,排除了 Hugs 的使用。

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}

-- a -> b means that the second type is uniquely determined by the
-- first. Without it, you would need explicitly type an expression
-- involving factor.
class VEC a b | a -> b  where
    factor :: a -> a -> b

instance VEC Int Int where
    -- a ~ Int, b ~ Int
    factor x y = x * y

-- newtype instead of data, for efficiency if nothing else
newtype Vector = VECTOR [Int] deriving (Show, Eq)

instance VEC Vector Int where
    -- a ~ Vector, b ~ Int
    factor (VECTOR xs) (VECTOR ys) = sum $ zipWith (*) xs ys


main = do
  print $ factor (3 :: Int) 3
  print $ factor (VECTOR [1,2,3]) (VECTOR [4,5,6])

没有函数依赖,你将不得不写

main = do
    print (factor (3 :: Int) 3 :: Int)
    print (factor (VECTOR [1,2,3]) (VECTOR [4,5,6]) :: Int)