I'm new to Haskell and am puzzling over how to best express some operations in the most idiomatic and clear way. Currently (there will be more to come) I'm puzzling over <*>
(I'm not even sure what to call that).
For example, if I have, say
f = (^2)
g = (+10)
as representative functions (in practice they are more complex, but the key thing here is that they are different and distinct), then
concatMap ($ [1,2,3,4,10]) [(f <$>), (g <$>) . tail . reverse]
and
concat $ [(f <$>), (g <$>) . tail . reverse] <*> [[1,2,3,4,10]]
accomplish the same thing.
Is one of these more idiomatic Haskell, does one imply something an experienced reader of Haskell that the other does not. Perhaps there are additional (better) ways to express exactly the same thing. Are there conceptual differences between the two approaches that a novice Haskeller like myself may be missing?
Both your functions (f <$>)
and (g <$>).tail.reverse
return a monoid type (list in this case) so you can use mconcat
to convert them into a single function. Then you can apply this function directly to the input list instead of wrapping it in another list and using concatMap
:
mconcat [(f <$>), (g <$>).tail.reverse] $ [1,2,3,4,10]
To expand on this, a function a -> b
is an instance of Monoid
if b
is a monoid. The implementation of mappend
for such functions is:
mappend f g x = f x `mappend` g x
or equivalently
mappend f g = \x -> (f x) `mappend` (g x)
so given two functions f
and g
which return a monoid type b
, f
mappendg
returns a function which applies its argument to f
and g
and combines the results using the Monoid
instance of b
.
mconcat
has type Monoid a => [a] -> a
and combines all the elements of the input list using mappend
.
Lists are monoids where mappend
== (++)
so
mconcat [(f <$>), (g <$>).tail.reverse]
returns a function like
\x -> (fmap f x) ++ (((fmap g) . tail . reverse) x)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With