xil*_*pex 10 haskell average pointfree function-composition applicative
我发现了这个平均函数的实现:
avg :: [Int] -> Int
avg = div . sum <*> length
Run Code Online (Sandbox Code Playgroud)
这是如何运作的?我查看了由于以下原因产生的函数div . sum:
(div . sum) :: (Integral a, Foldable t) => t a -> a -> a
Run Code Online (Sandbox Code Playgroud)
我明白这一点,但我无法说出<*> length它是如何工作的。
Wil*_*sem 13
<*> :: Applicative f => f (a -> b) -> f a -> f b是作用于结构的顺序应用函数Applicative。对于函数,这实现为 [src]:
Run Code Online (Sandbox Code Playgroud)instance Applicative ((->) r) where pure = const (<*>) f g x = f x (g x) liftA2 q f g x = q (f x) (g x)
所以f <*> g是\x -> f x (g x). 因此,这意味着在以下情况下avg:
avg = div . sum <*> length
Run Code Online (Sandbox Code Playgroud)
相当于:
avg x = (div . sum) x (length x)
Run Code Online (Sandbox Code Playgroud)
因此相当于:
avg x = div (sum x) (length x)
Run Code Online (Sandbox Code Playgroud)
所以它将sum x与分开length x。
我不喜欢这种特殊的 pointfree-trick。它使用Applicative (a->)实例作为“扇出”,将参数传递给两个单独的函数。本质上,这两个函数是sumand length,然后将结果组合回 by div,这可以用箭头组合器很好地表达(虽然有点冗长,因为箭头并没有真正以 Haskell 的默认柯里化风格播放):
import Control.Arrow
avg = uncurry div . (sum &&& length)
Run Code Online (Sandbox Code Playgroud)
在应用技巧中,您将组合函数合并到第一个共享参数的函数中。所以div . sum在这种情况下,另一个函数的结果length然后传递给第一个函数的第二个参数。
你也可以使用
avg = liftA2 div sum length
Run Code Online (Sandbox Code Playgroud)
它也使用Applicative实例。