Kr0e
Kr0e

Reputation: 2249

Haskell IO function type mismatch

what is the problem with the following code:

nextMatch :: (a -> Bool) -> [IO a] -> (IO a, [IO a])
nextMatch f (x:xs) = do
    s <- x
    if f s then (return x, xs)
        else nextMatch f xs

The compile error says:

src\Main.hs:364:10:
    Couldn't match expected type `(IO a, t0)' with actual type `IO a'
    In a stmt of a 'do' block: s <- x
    In the expression:
      do { s <- x;
           if f s then (return x, xs) else nextMatch f xs }
    In an equation for `nextMatch':
        nextMatch f (x : xs)
          = do { s <- x;
                 if f s then (return x, xs) else nextMatch f xs }

I want a function which searches a list for a match and returns the matched element plus the remaining list, as tuple.

I am still quite new to haskell, so this problem might be something quite simple...

Thanks! Chris

Upvotes: 1

Views: 223

Answers (3)

hammar
hammar

Reputation: 139930

You shouldn't need to deal with IO here. This is how I'd implement it as a pure function (I added the Maybe type since there might not be a next match):

nextMatch :: (a -> Bool) -> [a] -> Maybe (a, [a])
nextMatch _ []     = Nothing
nextMatch f (x:xs) = if f x then Just (x, xs) else nextMatch f xs

As a beginner, if you're taking something with IO as an input to a function, or if you're returning a data structure with IO inside of it, chances are you're probably doing something wrong (probably in the code you want to call this from).

Upvotes: 9

zurgl
zurgl

Reputation: 1930

As x if of type IO a , no need to re-return it, contrary to the tuple which definitely need to be injected into the monad.

if f s then return $ (x, xs)

But, that not the only issue, as your are into the IO monad and your signature doesn't reflect it, as you return type is (IO a, [IO a]) it should be IO (IO a, [IO a]). Then your code should be as follow.

nextMatch :: (a -> Bool) -> [IO a] -> IO (IO a, [IO a])
nextMatch f (x:xs) =  
  do 
    done <- fmap f x  
    if done
    then return $ (x, xs)
    else nextMatch f xs 

Anyway I don't know what you are trying to do but the signature of your function look pretty awkward. It should look much more like nextMatch :: (a -> Bool) -> [a] -> (a, [a]), then using return is enough to build a monadic version of it. nextMatchIO = return $ nextMatch and then plug this computation into your control flow using other function, provided by Control.Monad.

Upvotes: 1

LivingInformation
LivingInformation

Reputation: 119

Your function should be returning a tuple. If my Haskell is still up to par, I would try putting parens around your return function "if f s then (return (x, xs))".

Upvotes: -1

Related Questions