I found this implementation of the average function:
avg :: [Int] -> Int
avg = div . sum <*> length
How does this work? I looked at the function that was produced as a result of div . sum
div . sum
:
(div . sum) :: (Integral a, Foldable t) => t a -> a -> a
I understand that, but I'm unable to tell how <*> length
does the work.
<*> :: Applicative f => f (a -> b) -> fa -> fb
is the sequential application function that works on an Applicative
structure. For a function, this is implemented as [src] :
instance Applicative ((->) r) where pure = const liftA2 qfgx = q (fx) (gx)
so f <*> g
is short for \\x -> fx (gx)
. This thus means that in the case of avg
:
avg = div . sum <*> length
is equivalent to:
avg x = (div . sum) x (length x)
which is thus equivalent to:
avg x = div (sum x) (length x)
so it divides the sum x
with length x
.
I'm not a fan of this particular pointfree-trick. It uses the Applicative (a->)
instance as a “fanout”, to pass the argument to two separate functions. Essentially those two functions are sum
and length
, and the results are then combined back by div
, which can be expressed nicely with arrow combinators (albeit a bit more verbose, because arrows don't really play in Haskell's default curried style):
import Control.Arrow
avg = uncurry div . (sum &&& length)
In the applicative trick, you merge the combining function into the first argument-sharing one. So div . sum
div . sum
in this case, and the result of the other function length
is then passed into the second argument of the first function.
You can also use
avg = liftA2 div sum length
which uses the Applicative
instance too.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.