In Haskell, when I have to mix calls to fmap
/<$>
and >>=
/=<<
, I invariably end up with lots of parenthesis.
For example, here I'm calling listDirectoryAbs dir :: IO [String]
and then chaining a series of filter
and filterM
, ending with a fmap
.
findDlls :: String -> IO [String]
findDlls dir = f <$> (filterM predicate1 =<< (filter predicate2 <$> (filterM predicate3 =<< listDirectoryAbs dir)))
Because all these nested expressions look messy (at least to me), I end up rewriting f <$> x
to return . f =<< x
. If I then flip the binds, I get something more readable:
findDlls dir = listDirectoryAbs dir
>>= filterM predicate3
>>= return . filter predicate2
>>= filterM predicate1
>>= return . f
Is rewriting f <$> x
-> return . f =<< x
-> x >>= return . f
"bad" in any way? Is there a preferable way of avoiding nested expressions in situations such as these?
I could use do
notation instead, but I'd like to avoid having to be explicit about data flow and giving every return value a name.
I don't think it's "bad" (unless it forfeits optimisations in fmap
of that particular monad), however I don't like its verbosity.
I'd rather define my own operator for this, <$$>
has been suggested or <&>
would match the $
/&
-duality well (see also Anyone ever flip (<$>)):
infixl 1 <&>
(<&>) = flip (<$>)
findDlls dir = listDirectoryAbs dir
>>= filterM predicate3
<&> filter predicate2
>>= filterM predicate1
<&> f
Btw, if your monad is an Arrow
(e.g. functions), then <<<
/>>>
combines nicely with =<<
/>>=
.