理解Haskell中的一个无点函数中的`ap` [英] Understanding `ap` in a point-free function in Haskell
问题描述
addOne x = 1 + x $ b我可以理解Haskell中的免费函数的基本知识: $ b
正如我们在等式两边都看到x,我们简化它:
addOne =(+ 1)
令人难以置信的是,在不同部分使用相同参数两次的函数可以无点写!
让我以平均值
函数作为基本示例:
平均值xs = realToFrac(总和xs)/ genericLength xs
简化<$ c $似乎是不可能的c> xs ,但是 http://pointfree.io/ 出来了:
average = ap((/)。realToFrac。sum)genericLength
这是有效的。
据我的理解, ap $相同c $ c>在两个函数中,
(/)的组成。 realToFrac。 sum
和 genericLength
不幸的是 ap
函数对我来说没有任何意义,文档 http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:ap 州:
ap :: Monad m => m(a - > b) - > m a - > m b
在很多情况下,liftM操作可以用ap,
来代替,这可以促进功能应用。
return f`ap` x1`ap` ...`ap` xn
相当于
liftMn f x1 x2 ... xn
但写作:
let average = liftM2((/)。realToFrac。sum)genericLength
(提供了一个非常长的类型错误信息,请问我会包含它),所以我不明白这些文档试图说什么。
表达式 ap((/)。realToFrac。sum)genericLength
是如何工作的?你可以用简单的术语解释 ap
吗?
monad m
是( - >)a
,您可以定义 ap
如下:
ap fg = \ x - > fx(gx)
我们可以看到,这确实起作用。 >
average = ap((/)。realToFrac。sum)genericLength
average = \ x - > ((/)。realToFrac。sum)x(genericLength x)
average = \ x - > (/)(realToFrac(sum x))(genericLength x)
average = \ x - > realToFrac(sum x)/ genericLength x
我们也可以派生 ap
来自一般法律
ap fg = do ff < - f; gg < - g; return(ff gg)
即解除 do
-notation
ap fg = f>> = \ff - > g>> = \gg - >如果我们用monad方法的定义代替$ b $,那么
m>> = f = \ x - > f(m x)x
return x = \_ - > x
我们得到 ap
(对于我们特定的monad ( - >)a
)。事实上:
app f g
= f>> = \ff - > g>> = \gg - > return(ff gg)
= f>> = \ff - > g>> = \gg - > \_ - > ff gg
= f>> = \ff - > g>> = \gg _ - > ff gg
= f>> = \ff - > \x - > (\g_gf)(g x)x
= f>> = \ff - > \x - > (\_-> ff(g x))×
= f>> = \ff-> \x - > ff(g x)
= f>> = \ff x - > ff(g x)
= \y - > (\ff x - > ff(g x))(f y)y
= \ y - > (\ x - > f y(g x))y
= \ y - > f y(g y)
I am able to understand the basics of point-free functions in Haskell:
addOne x = 1 + x
As we see x on both sides of the equation, we simplify it:
addOne = (+ 1)
Incredibly it turns out that functions where the same argument is used twice in different parts can be written point-free!
Let me take as a basic example the average
function written as:
average xs = realToFrac (sum xs) / genericLength xs
It may seem impossible to simplify xs
, but http://pointfree.io/ comes out with:
average = ap ((/) . realToFrac . sum) genericLength
That works.
As far as I understand this states that average
is the same as calling ap
on two functions, the composition of (/) . realToFrac . sum
and genericLength
Unfortunately the ap
function makes no sense whatsoever to me, the docs http://hackage.haskell.org/package/base-4.8.1.0/docs/Control-Monad.html#v:ap state:
ap :: Monad m => m (a -> b) -> m a -> m b
In many situations, the liftM operations can be replaced by uses of ap,
which promotes function application.
return f `ap` x1 `ap` ... `ap` xn
is equivalent to
liftMn f x1 x2 ... xn
But writing:
let average = liftM2 ((/) . realToFrac . sum) genericLength
does not work, (gives a very long type error message, ask and I'll include it), so I do not understand what the docs are trying to say.
How does the expression ap ((/) . realToFrac . sum) genericLength
work? Could you explain ap
in simpler terms than the docs?
解决方案 When the monad m
is (->) a
, as in your case, you can define ap
as follows:
ap f g = \x -> f x (g x)
We can see that this indeed "works" in your pointfree example.
average = ap ((/) . realToFrac . sum) genericLength
average = \x -> ((/) . realToFrac . sum) x (genericLength x)
average = \x -> (/) (realToFrac (sum x)) (genericLength x)
average = \x -> realToFrac (sum x) / genericLength x
We can also derive ap
from the general law
ap f g = do ff <- f ; gg <- g ; return (ff gg)
that is, desugaring the do
-notation
ap f g = f >>= \ff -> g >>= \gg -> return (ff gg)
If we substitute the definitions of the monad methods
m >>= f = \x -> f (m x) x
return x = \_ -> x
we get the previous definition of ap
back (for our specific monad (->) a
). Indeed:
app f g
= f >>= \ff -> g >>= \gg -> return (ff gg)
= f >>= \ff -> g >>= \gg -> \_ -> ff gg
= f >>= \ff -> g >>= \gg _ -> ff gg
= f >>= \ff -> \x -> (\gg _ -> ff gg) (g x) x
= f >>= \ff -> \x -> (\_ -> ff (g x)) x
= f >>= \ff -> \x -> ff (g x)
= f >>= \ff x -> ff (g x)
= \y -> (\ff x -> ff (g x)) (f y) y
= \y -> (\x -> f y (g x)) y
= \y -> f y (g y)
这篇关于理解Haskell中的一个无点函数中的`ap`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!