Reputation: 3126
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
Upvotes: 1
Views: 824
Reputation: 30237
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.
Upvotes: 4
Reputation: 47062
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)
.
Upvotes: 3