Car*_*orc 15 haskell functional-programming pointfree
我能够理解Haskell中无点函数的基础知识:
addOne x = 1 + x
Run Code Online (Sandbox Code Playgroud)
当我们在等式的两边看到x时,我们简化它:
addOne = (+ 1)
Run Code Online (Sandbox Code Playgroud)
令人难以置信的是,在不同的部分中使用相同参数两次的函数可以无点编写!
让我把这个average函数作为一个基本的例子写成:
average xs = realToFrac (sum xs) / genericLength xs
Run Code Online (Sandbox Code Playgroud)
似乎无法简化xs,但http://pointfree.io/提出:
average = ap ((/) . realToFrac . sum) genericLength
Run Code Online (Sandbox Code Playgroud)
这样可行.
据我所知,这说明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
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
Run Code Online (Sandbox Code Playgroud)
但写作:
let average = liftM2 ((/) . realToFrac . sum) genericLength
Run Code Online (Sandbox Code Playgroud)
不起作用,(给出一个很长的类型错误信息,问我会包括它),所以我不明白文档试图说什么.
表达式如何ap ((/) . realToFrac . sum) genericLength工作?你能用ap更简单的术语解释文件吗?
任何lambda术语都可以重写为仅使用一组合适的组合子而不使用lambda抽象的等效术语.此过程称为abstraciton消除.在此过程中,您希望从内到外删除lambda抽象.因此,在一个步骤中,您必须?x.M在那里M已经是游离λ抽象的,你想摆脱x.
M是x,则替换?x.x为id(id通常用I组合逻辑表示).M不包含x,则用术语替换const M(const通常用K组合逻辑表示).如果M是PQ,那就是术语?x.PQ,你想要"推" x到函数应用程序的两个部分内部,这样你就可以递归地处理这两个部分.这是通过使用S定义为的组合子来实现的?fgx.(fx)(gx),也就是说,它需要两个函数并传递x给它们,并将结果一起应用.您可以轻松验证它?x.PQ是否等效S(?x.P)(?x.Q),并且我们可以递归地处理这两个子项.
如其他答案中所述,S组合器在Haskell中可用作ap(或<*>)专用于阅读器monad.
读者monad的外观并非偶然:当解决?x.M用等效函数替换的任务基本上是提升M :: a到读者monad r -> a(实际上读者应用部分就够了),其中r的类型是x.如果我们修改上述流程:
M为x.然后我们"抬" x到id,摆脱变量.下面的其他案例只是将表达式提升到应用程序仿函数的机械应用程序:?x.M,其中M不包含x,它只是举起M读者应用性,这是pure M.的确,因为(->) r,pure等同于const.<*> :: f (a -> b) -> f a -> f b功能应用程序被解除为monad/applicative.这正是我们所做的:我们提升了两个部分P和Q阅读器应用程序,然后用<*>它们将它们绑定在一起.通过添加更多的组合器可以进一步改善该过程,这使得所得的术语更短.大多数情况下,组合子B和C使用,这在Haskell对应功能(.)和flip.再次,(.)只是fmap/ <$>为读者应用.(我不知道这样的内置函数用于表达flip,但它被视为f (a -> b) -> a -> f b读者应用程序的专门化.)
前段时间我写了一篇关于此的短篇文章:Monad读者第17期,读者Monad和抽象消除.
当monad m是(->) a,就像你的情况一样,你可以定义ap如下:
ap f g = \x -> f x (g x)
Run Code Online (Sandbox Code Playgroud)
我们可以看到这确实在您的无点示例中"有效".
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
Run Code Online (Sandbox Code Playgroud)
我们也可以ap从一般法律中得出
ap f g = do ff <- f ; gg <- g ; return (ff gg)
Run Code Online (Sandbox Code Playgroud)
也就是说,贬低了do注释
ap f g = f >>= \ff -> g >>= \gg -> return (ff gg)
Run Code Online (Sandbox Code Playgroud)
如果我们替换monad方法的定义
m >>= f = \x -> f (m x) x
return x = \_ -> x
Run Code Online (Sandbox Code Playgroud)
我们得到了之前的apback(对于我们特定的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 -> (\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)
Run Code Online (Sandbox Code Playgroud)