简体   繁体   中英

Haskell - How does this average function work?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM