无点在Haskell [英] Point-free in Haskell

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

问题描述

我有这个代码,我想要免点;



(\kt - > chr $ a + flip mod 26(ord k + ord t -2 * a))



我如何做?



除了想想这个amd想出什么东西之外,还有一些点自由风格的一般规则?

解决方案

要打开一个函数

  func xyz =(x,y和z中的某个表达式)

为无点形式,我通常尝试按照最后一个参数 z 并将函数写为

  func xyz =(使用x和y创建的某些函数管道)z 

然后我可以取消 z get

  func xy =(使用x和y创建的某些函数管道)
/ pre>

然后重复这个过程,y和x应该以 func 以无点形式结束。在这个过程中识别的重要转换是:

  fz = foo $ bar z-或fz = foo(bar z) 
< => f z = foo。 bar $ z
< => f = foo。 bar

还有一点要记住,使用部分评估,你可以一个函数:

  foo $ bar xy == foo。 bar x $ y  -  foo应用于((bar x)应用于y)

函数,考虑 k t 的流程:


  1. ord 应用于其中每一个

  2. 添加结果

  3. 减去2 * a

  4. 取结果mod 26

  5. 添加

  6. code> chr

作为第一次尝试简化,我们得到:

  func kt = chr。 (+ a)。 (`mod` 26)。减去(2 * a)$ ord k + ord t 

注意,您可以避免<$ c $通过使用 mod 上的一个部分,使用 - Haskell因此有一个减法函数(他们与编写负数的语法冲突:( - 2)表示负2 ,并且与减去2 不同)。



在此函数中, ord k + ord t 是使用 Data.Function.on link )。这个有用的组合器让我们用 k 替换 ord k + ord t t

  func kt = chr。 (+ a)。 (`mod` 26)。减去(2 * a)$((+)`on` ord)kt 



非常接近

  func kt =(function pipeline)kt 

,因此

  func =(function pipeline)$ b $不幸的是,Haskell在使用一系列一元函数来构造一个二进制函数时有点混乱,但是有一个一个窍门(我会看看,如果我能找到一个很好的参考),我们最终得到:

  import Data 。function(on)

func =((chr。(+ a)。(`mod` 26)。subtract(2 * a))。 (+)`on` ord)

这几乎是一个不错的无点免费函数管道,除了那个丑陋的伎俩。通过定义。:运算符=nofollow noreferrer>,这整理了一点:

  import Data.Function on)

(。:) =(。)。(。)

func =(chr。 * a))::((+)`on` ord)

您可以添加一些帮助函数来分隔来自 Caesar密码的字母< - > Int conversion算术。例如: letterToInt =减去a。 ord


I have this code that I want to make point-free;

(\k t -> chr $ a + flip mod 26 (ord k + ord t -2*a))

How do I do that?

Also are there some general rules for point free style other than "think about this amd come up with something"?

解决方案

To turn a function

func x y z = (some expression in x, y and z)

into point-free form, I generally try to follow what is done to the last parameter z and write the function as

func x y z = (some function pipeline built using x and y) z

Then I can cancel out the zs to get

func x y = (some function pipeline built using x and y)

Then repeating the process for y and x should end up with func in point-free form. An essential transformation to recognise in this process is:

    f z = foo $ bar z    -- or f z = foo (bar z)
<=> f z = foo . bar $ z
<=> f   = foo . bar

It's also important to remember that with partial evaluation, you can "break off" the last argument to a function:

foo $ bar x y == foo . bar x $ y    -- foo applied to ((bar x) applied to y)

For your particular function, consider the flow that k and t go through:

  1. Apply ord to each of them
  2. Add the results
  3. Subtract 2*a
  4. Take the result mod 26
  5. Add a
  6. Apply chr

So as a first attempt at simplifying, we get:

func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ord k + ord t

Note that you can avoid flip by using a section on mod, and sections using - get messy in Haskell so there's a subtract function (they clash with the syntax for writing negative numbers: (-2) means negative 2, and isn't the same as subtract 2).

In this function, ord k + ord t is an excellent candidate for using Data.Function.on (link). This useful combinator lets us replace ord k + ord t with a function applied to k and t:

func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ((+) `on` ord) k t

We're now very close to having

func k t = (function pipeline) k t

and hence

func = (function pipeline)

Unfortunately Haskell is a bit messy when it comes to composing a binary function with a sequence of unary functions, but there is a trick (I'll see if I can find a good reference for it), and we end up with:

import Data.Function (on)

func = ((chr . (+a) . (`mod` 26) . subtract (2*a)) .) . ((+) `on` ord)

which is almost a nice neat point-free function pipeline, except for that ugly composing trick. By defining the .: operator suggested in the comments on this page, this tidies up a little to:

import Data.Function (on)

(.:) = (.).(.)

func = (chr . (+a) . (`mod` 26) . subtract (2*a)) .: ((+) `on` ord)

To polish this some more, you could add some helper functions to separate the letter <-> Int conversion from the Caesar cipher arithmetic. For example: letterToInt = subtract a . ord

这篇关于无点在Haskell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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