理解Haskell中的一个无点函数中的`ap` [英] Understanding `ap` in a point-free function in Haskell

查看:104
本文介绍了理解Haskell中的一个无点函数中的`ap`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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 

这是有效的。



据我的理解, average 是与调用 ap 在两个函数中,(/)的组成。 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆