I'm new to haskell and nothing I've read online really helped me with this. My assignment is to implement a typeclass VEC that has a function factor which either calculates the multiplication of two Integers or performs the dot product of two matrices if the user input wasn't two numbers but instead two lists of integers of type vector. My code looks as follows:
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)
I assumed the Vectors were of type [Int]
but now I'm not so sure, since I get the following error message when trying to compile the code using Hugs:
Hugs> :l kdp
ERROR file:kdp.hs:7 - Type error in instance member binding
*** Term : []
*** Type : [a]
*** Does not match : Vector
So my questions would be: What does the first line actually mean? It was given along with the assignment and I've seen many similar definitions of data types but none with this particular pattern. And then how do I fix the problem of not being able to use predefined functions such as tail
or in the above error case comparing a list of Integers with my custom data type? My guess is I have to define the operations on my own but I couldn't figure out how to do that.
When you write an instance for a class like
class C a where
method :: a -> a
you replace all of the parameter appearances ( a
) with the type you are writing instance for. For example in your case:
{-# LANGUAGE InstanceSigs #-}
instance VEC Vector where
factor :: Vector -> Vector -> Vector
factor _ _ = undefined
So you cannot match arguments of type Vector
with pattern []
nor use head
nor tail
functions on it as they are working on lists. However, your Vector
consists of lists, so you can simply unpack it:
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]
This is very ugly and partial tho, you can use some builtin Data.List
machinery to make it more sexy:
instance VEC Vector where
factor (Vector xs) (Vector ys) =
Vector [sum (zipWith (*) xs ys)]
As you are using deriving (Show, Eq)
, the ==
operator should just work.
You can generalize your type class to take two type variables to accommodate the two different operations of integer multiplication and vector dot products. This requires two GHC-specific extensions, though, precluding your use of 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])
Without the functional dependency, you would have to write
main = do
print (factor (3 :: Int) 3 :: Int)
print (factor (VECTOR [1,2,3]) (VECTOR [4,5,6]) :: Int)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.