`

haskell - types and typeclasses - type parameters

阅读更多

A value constructor can take some values parameters and then produce a new value. For instance, the Car constructor takes three values and produces a car value. In a similar manner, type constructors can take types as parameters to produce new types. This might sound a bit too meta at first, but it's not that complicated. If you're familiar with templates in C++, you'll see some parallels. To get a clear picture of what type parameters work like in action, let's take a look at how a type we've already met is implemented.

an example of this is as below.

data Maybe a = Nothing | Just a  

 as the example shows here, a is a t ype paramter, because there is a type paramter involved, we call maybe a type constructor, Depending on what we want this data type to hold when it is not nothing. We may end up with Maybe Int, Maybe Car.. 

 

  • type parameter
  • type constraint

Let's first see  some type without type parameter 

-- file 
--   Car2.hs
-- description: 
--   a car with a more variant things than others 

module Car
(Car(..)
) where 

-- the car record type does not use the Record syntax 
data Car = Car { company :: String  
               , model :: String  
               , year :: Int  
               } deriving (Show)  
tellCar :: Car -> String  
tellCar (Car {company = c, model = m, year = y}) = "This " ++ c ++ " " ++ m ++ " was made in " ++ show y  


-- use the following to test the tellCar funciton 
-- tellCar ( Car {company="Ford", model="Mustang", year=1967}  )


 

then we compare that with the type parameter what we can do ..

                     , model :: b
                     , year :: c
                     } deriving (Show)


tellCar :: (Show a) => Car String String a -> String
-- does this mean that you have created an alias to company with c,and alias to model with m and alias to year with y
tellCar (Car {company = c, model = m, year = y}) = "This " ++ c ++ " " ++ m ++ " was made in " ++ show y

 the type parameter has parameterized type, such as the following. Data.Map type, which has a 

Map k v

 but there is some requirement on the key type, it has to be an Ord typeclass instance, so that we can do comparison on the key and we can sort keys with the same hash value. 

so, her e is what you can do to specify the type constraint. 

 

data (Ord k) => Map k v = ...  

 

But normally we don't put the constraint on the data declaration, if we don't put the constraint on the data declaration, we are going to have to put the constraint into functions that assmes the keys in a map can be ordered. But if we don't put the constraint in the data declaration, we don't have to put (Ord k) => in the type declaration of functions that don't care whether the jeys can be odered. e.g. of this is the unction is toList, that just takes a mapping and converts it to an associative list. Its type signature istoList :: Map k a -> [(k, a)]. If Map k v had a type constraint in its data declaration, the type for toList would have to be toList :: (Ord k) => Map k a -> [(k, a)], even though the function doesn't do any comparing of keys by order.


Let's see yet another example , this time, we will make a Vector type, 

 

-- file
--   type_paramter.hs
-- description:
--    this is a type paramter illustration on the map types

module Vector
( Vector(..)
) where 



-- If we were defining a mapping type, we could add a typeclass constraint in the data declaration:
-- data (Ord k) => Map K v = ... 

-- NOTE:  it's a very strong convention in Haskell to never add typeclass constraints in data declarations. Why?



data Vector a = Vector a a a deriving (Show)  
-- vector plus
vplus :: (Num t) => Vector t -> Vector t -> Vector t  
(Vector i j k) `vplus` (Vector l m n) = Vector (i+l) (j+m) (k+n)  
-- vector Mult  
vectMult :: (Num t) => Vector t -> t -> Vector t  
(Vector i j k) `vectMult` m = Vector (i*m) (j*m) (k*m)  
-- vector scalarMult  
scalarMult :: (Num t) => Vector t -> Vector t -> t  
(Vector i j k) `scalarMult` (Vector l m n) = i*l + j*m + k*n  

-- NOTE on the vector classes
--    note that the vector class can only operate on the same Vector class and can work on Float, Int, and Double. 


-- 
-- ghci> Vector 3 5 8 `vplus` Vector 9 2 8  
-- Vector 12 7 16  
-- ghci> Vector 3 5 8 `vplus` Vector 9 2 8 `vplus` Vector 0 2 3  
-- Vector 12 9 19  
-- ghci> Vector 3 9 7 `vectMult` 10  
-- Vector 30 90 70  
-- ghci> Vector 4 9 5 `scalarMult` Vector 9.0 2.0 4.0  
-- 74.0  
-- ghci> Vector 2 9 3 `vectMult` (Vector 4 9 5 `scalarMult` Vector 9 2 4)  
-- Vector 148 666 222  

 

Once again, it's very important to distinguish between the type constructor and the value constructor. When declaring a data type, the part before the = is the type constructor and the constructors after it (possibly separated by |'s) are value constructors. Giving a function a type of Vector t t t -> Vector t t t -> t would be wrong, because we have to put types in type declaration and the vector type constructor takes only one parameter, whereas the value constructor takes three. Let's play around with our vectors. 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics