I have the following in a module Util
that I use widely without issues:
(>~) = flip fmap
infix 8 >~
(>>~) :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)
(>>~) = Control.Monad.forM
infix 8 >>~
(The explicit type sig is only because despite the bleedingly obvious "it's just an alias for a built-in func" GHC couldn't figure this out and forced me to, so let's ignore this here.)
NOW, in another module (same project) I import the above operators and oddly enough, the following few lines DO compile just-fine:
listAllFiles rootdirpath reldirs modtimer =
let allfiles = (dirpaths >>~ foreachdir) >~~ concat
(>~~) = flip fmap
infix 8 >~~
...
But the following variation (which I'd prefer obviously) will fail to compile:
listAllFiles rootdirpath reldirs modtimer =
let allfiles = (dirpaths >>~ foreachdir) >~ concat
...
Isn't that odd, given how the successful >~~
declared locally right above was defined in exactly the very identical way as the imported >~
?
Where's the logic in that, can anyone share their insights on this? Oh, here's the error:
Files.hs:88:21: error:
* Couldn't match type `IO' with `[]'
Expected type: [[[(FilePath, Data.Time.Clock.UTCTime)]]]
Actual type: IO [[(FilePath, Data.Time.Clock.UTCTime)]]
* In the first argument of `(>~)', namely
`(dirpaths >>~ foreachdir)'
In the expression: (dirpaths >>~ foreachdir) >~ concat
In an equation for `allfiles':
allfiles = (dirpaths >>~ foreachdir) >~ concat
.. but obviously this question isn't about how to deal with "Couldn't match type 'a' with 'b'" errors per-se / in the general case --- keep in mind in a functional language I expect identical definitions to work identically, whether defined in a local let
or in an imported module. What in the heck could be disrupting this general principle in this specific instance?
It's not a show-stopper, I could skip the fancy ops go fmap concat (etc)
and just get on with business. But I guess there's maybe something deeper to learn here (or an obscure bug encountered to be reported)!