Reputation: 190799
I'm trying to make a function that returns a list of assoc type that I defined from two lists. I think about using list comprehension, but I'm not sure how to get a value from each list.
type Assoc k v = [(k, v)]
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc k v =
[Assoc k' v' | k' <- k, ???]
main :: IO ()
main = do
putStrLn $ show makeAssoc [1,2,3] [4,5,6]
How to implement the makeAssoc k v
?
Upvotes: 0
Views: 944
Reputation: 764
You have defined Assoc k v
as an alias (type
does not create a distinct type, just gives an existing type a new name - they are still interchangeable) for a list of (k, v)
. According to the makeAssoc type signature, it returns a list of Assoc k v
. Which means that it actually returns a list of list of (k, v)
and that is probably not what you want. Two possible solutions:
Solution 1 - Keep Assoc k v
as a list of tuples and remove the [] from the type signature of makeAssoc
type Assoc k v = [(k, v)]
makeAssoc :: [k] -> [v] -> Assoc k v
Solution 2 - Make Assoc k v
an alias for a tuple (not a list of tuples) and keep the [] in the type signature of makeAssoc
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
Another problem is thattype Assoc k v
creates the alias Assoc k v
that you can use on type signatures, but it doesn't create an actual distinct type with a corresponding data constructor. So you can't use Assoc k v
on the actual implementation of the function. That means we are working with simple tuples and the correct syntax for list comprehensions would be (using the second solution from before):
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = [(k, v) | k <- ks, v <- vs]
But list comprehensions will give you every possible pair using one element from each list. Exampe: makeAssoc [1, 2] [3, 4]
will result in [(1, 3), (1, 4), (2, 3), (2, 4)]
. If you actually want a one to one direct mapping, you should use zip
.
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = zip ks vs
With this implementation, the result would be [(1, 3), (2, 4)]
.
Edit:
Going further: when you get more experienced in Haskell, you will learn that you could have written the same thing as:
type Assoc k v = (k, v)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc = zip
Another thing: If you wanted an actual distinct type, you could have used the data
keyword and the zipWith
function.
data Assoc k v = Assoc k v
deriving (Show)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc ks vs = zipWith Assoc ks vs
Or omitting the parameters as before:
data Assoc k v = Assoc k v
deriving (Show)
makeAssoc :: [k] -> [v] -> [Assoc k v]
makeAssoc = zipWith Assoc
Learn you a Haskell is a great resource for a beginner and should help you understand all this and much more.
Upvotes: 5