yet another monad question

I have the following code which works fine: type File = (String, String) --name and content readDir :: String -> IO [File] readDir dir = findRegularFiles dir >>= readFiles where findRegularFiles = find always (fileType ==? RegularFile) readFiles paths = mapM readFile paths >>= return.zip paths ...and I would like to write the function readDir like this: readDir :: String -> IO [File] readDir = findRegularFiles >>= readFiles where ... ...but I get the error: grep.hs:46:32: Couldn't match expected type `IO [FilePath]' with actual type `[FilePath]' Expected type: IO [FilePath] -> String -> IO [File] Actual type: [FilePath] -> IO [File] In the second argument of `(>>=)', namely `readFiles' In the expression: findRegularFiles >>= readFiles Can somebody please explain it? It's not a big deal. I can keep the old version which works fine. My only problem is that I thought I understood the monads better but apparently I don't :)

When you pass an argument to
readDir = findRegularFiles >>= readFiles
it expands to
readDir arg = (findRegularFiles >>= readFiles) arg
which fails because that expression takes no argument, only
findRegularFiles does. Honestly I can't think of any way to get that
argument in there without explicitly naming it.
And no, you cannot go like this either:
readDir = readFiles =<< findRegularFiles
It still has the same problem.
On Sat, Feb 4, 2012 at 5:49 AM, Ovidiu Deac
I have the following code which works fine:
type File = (String, String) --name and content
readDir :: String -> IO [File] readDir dir = findRegularFiles dir >>= readFiles where findRegularFiles = find always (fileType ==? RegularFile) readFiles paths = mapM readFile paths >>= return.zip paths
...and I would like to write the function readDir like this: readDir :: String -> IO [File] readDir = findRegularFiles >>= readFiles where ...
...but I get the error: grep.hs:46:32: Couldn't match expected type `IO [FilePath]' with actual type `[FilePath]' Expected type: IO [FilePath] -> String -> IO [File] Actual type: [FilePath] -> IO [File] In the second argument of `(>>=)', namely `readFiles' In the expression: findRegularFiles >>= readFiles
Can somebody please explain it?
It's not a big deal. I can keep the old version which works fine. My only problem is that I thought I understood the monads better but apparently I don't :)
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Sat, Feb 4, 2012 at 12:05 PM, David McBride
When you pass an argument to readDir = findRegularFiles >>= readFiles
it expands to readDir arg = (findRegularFiles >>= readFiles) arg
which fails because that expression takes no argument, only findRegularFiles does. Honestly I can't think of any way to get that argument in there without explicitly naming it.
I would say the problem is even before that, the expression "findRegularFiles >>= readFiles" is not well typed : (>>=) :: Monad m => m a -> (a -> m b) -> m b specialized here in : (>>=) :: IO a -> (a -> IO b) -> IO b but : findRegularFiles :: FilePath -> IO [FilePath] so findRegularFiles is not of type "IO a", so can't be the first argument of (>>=) (or the second of (=<<) since that's just the flipped version). But there is a solution ! What you're searching here is a function of type : ? :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) A kind of monadic composition, there is an operator for that in Control.Monad since ghc 6.12 or even before : (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) so :
readDir = findRegularFiles >=> readFiles
or
readDir = readFiles <=< findRegularFiles
will work :) -- Jedaï

thanks for the explanations! I guess it's clear now
On Sat, Feb 4, 2012 at 3:02 PM, Chaddaï Fouché
On Sat, Feb 4, 2012 at 12:05 PM, David McBride
wrote: When you pass an argument to readDir = findRegularFiles >>= readFiles
it expands to readDir arg = (findRegularFiles >>= readFiles) arg
which fails because that expression takes no argument, only findRegularFiles does. Honestly I can't think of any way to get that argument in there without explicitly naming it.
I would say the problem is even before that, the expression "findRegularFiles >>= readFiles" is not well typed :
(>>=) :: Monad m => m a -> (a -> m b) -> m b specialized here in : (>>=) :: IO a -> (a -> IO b) -> IO b
but :
findRegularFiles :: FilePath -> IO [FilePath]
so findRegularFiles is not of type "IO a", so can't be the first argument of (>>=) (or the second of (=<<) since that's just the flipped version).
But there is a solution ! What you're searching here is a function of type : ? :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
A kind of monadic composition, there is an operator for that in Control.Monad since ghc 6.12 or even before :
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
so :
readDir = findRegularFiles >=> readFiles
or
readDir = readFiles <=< findRegularFiles
will work :)
-- Jedaï

It's not about monads, that this doesn't work. To go point-free you
need to understand the types of the expressions you compose.
The bind function ((>>=) :: Monad m => m a -> (a -> m b) -> m b)
doesn't leave room to take more arguments. Matching the arguments to
bind in the expression 'findRegularFiles >>= readFiles' the
'findRegularFiles' should have a type of 'Monad m => m a' and
'readFiles' 'Monad m => a -> m b'. With this type 'findRegularFiles'
takes no arguments, but it should take one -- the directory-path. But
the 'readFiles' type looks to be right: bind expects a function from
'a' to 'm b', and that's what it gets. So, what you need is some other
function than bind (>>=) to compose the functions you have to get the
whole expression to have the right type. If you find the type of that
function, you'll easily find the composing function itself.
Also check the definitions of 'findRegularFiles' and 'readFiles', but
at first you can leave them be
... where
findRegularFiles :: String -> IO [String]
findRegularFiles dir = undefined
readFiles :: [String] -> IO [File]
readFiles paths = undefined
and implement them later.
On Sat, Feb 4, 2012 at 12:49 PM, Ovidiu Deac
I have the following code which works fine:
type File = (String, String) --name and content
readDir :: String -> IO [File] readDir dir = findRegularFiles dir >>= readFiles where findRegularFiles = find always (fileType ==? RegularFile) readFiles paths = mapM readFile paths >>= return.zip paths
...and I would like to write the function readDir like this: readDir :: String -> IO [File] readDir = findRegularFiles >>= readFiles where ...
...but I get the error: grep.hs:46:32: Couldn't match expected type `IO [FilePath]' with actual type `[FilePath]' Expected type: IO [FilePath] -> String -> IO [File] Actual type: [FilePath] -> IO [File] In the second argument of `(>>=)', namely `readFiles' In the expression: findRegularFiles >>= readFiles
Can somebody please explain it?
It's not a big deal. I can keep the old version which works fine. My only problem is that I thought I understood the monads better but apparently I don't :)
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- Markus Läll
participants (4)
-
Chaddaï Fouché
-
David McBride
-
Markus Läll
-
Ovidiu Deac