1
votes

I am trying to do some self-learning with Haskell.

A function loadData reads some data off the file and based on an integer parameter does some processing on it to produce a Map. I need to create two such maps and apply a cosine similarity metric to it.I am trying to find the intersection of the two maps first. However, I run into a type error (Couldn't match expected type `a0 -> Map.Map k0 a1' with actual type `IO (Map.Map [Char] Double)') How can I feed the output of loadData to Map.intersection. Do I need a function applicator $?

loadData :: Int -> FilePath -> IO (Map.Map [Char] Double)

Map.intersection :: Ord k => Map.Map k a -> Map.Map k b -> Map.Map k a
2
Do you know how to handle IO yet?fuz
How are you trying to feed the output of loadData to Map.intersection? Show us your code.dave4420
I just tried doing Map.intersection <$>(loadData 1 "firstFile") <$>(loadData 1 "secondFile")atlantis

2 Answers

4
votes

As FUZxxl has mentioned in a comment to your question, I question how much you've looked into Haskell I/O. This is one of the big initial hurdles to get over to make use of the language, and it seems like you'd want to start with simpler tasks.

But still, to answer your question more literally, here's two ways. First, the elementary one, the one you need to understand first before the other ones make sense:

processData :: Int -> FilePath -> Int -> FilePath -> IO (Map.Map [Char] Double)
processData int1 path1 int2 path2 =
    do map1 <- loadData int1 path1
       map2 <- loadData int2 path2
       return (Map.intersection map1 map2)

There are more advanced answers that involve abstracting the pattern shown above into a function. The more basic way to do this is to use the liftM2 function from the Control.Monad module. I'll give an example implementation of liftM2 just to make it obvious how it's related to the code above:

liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f mx my = do x <- mx
                    y <- my
                    return (f x y)

With liftM2, we can rewrite processData this way:

processData :: Int -> FilePath -> Int -> FilePath -> IO (Map.Map [Char] Double)
processData int1 path1 int2 path2 =
    liftM2 Map.intersection (loadData int1 path1) (loadData int2 path2)

dave4420's answer is a bit more advanced; what it comes down to is that Control.Applicative has two operators (<$> and <*>) that in combination can do the same thing as liftM2, but for an arbitrary number of arguments for the function that liftM2 takes as its first argument.

3
votes

Something like this:

import Control.Applicative

Map.intersection <$> loadData param filename1 <*> loadData param filename2

Note that the result of this has type IO (Map.Map String Double).