免费在Haskell [英] Point-free in 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
获取
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应用于((x x))应用于y)
功能,考虑
k
和t
的流程:
- 将
ord
应用于每个
- 添加结果
- 减去2 * a
- 取结果mod 26
- 添加
- code> chr
所以作为简化的第一个尝试,我们得到:
func kt = chr。 (+ a)。 (`mod` 26)。减去(2 * a)$ ord k + ord t
请注意,您可以避免
flip
通过使用mod
上的一节,使用-
的部分会弄乱Haskell,所以有一个减法
函数(他们与写负数的语法冲突:( - 2)
表示负2 ,并且不相同subtract 2
)。
在此函数中,
ord k + ord t
是使用Data.Function.on
(链接)。这个有用的组合器让我们用k
和的函数替换
:ord k + ord t
tfunc kt = chr。 (+ a)。 (`mod` 26)。减去(2 * a)$((+)`on` ord)kt
非常接近于
func kt =(function pipeline)kt
因此
func =(function pipeline)
不幸的是,当组合一系列一元函数的二进制函数时,Haskell有点混乱,但是一个技巧(我会看看我能否找到一个很好的参考),我们最终得到:
导入数据
func =((chr。(+ a)。(`mod` 26)。subtract(2 * a)))。 ((+)`on` ord)
这几乎是一个很好的无点无功功能管道,除了那个丑陋的戏法。通过在评论。:运算符=noreferrer>在这个页面上,这个整理了一点:
import Data.Function )
(。:) =(。)。(。)
func =(chr。(+ a)。(`mod` 26)。subtract(2 * a))。:((+)`on` ord)
可以添加一些帮助函数,以从凯撒密码算术中分离字母< - > Int转换。例如:
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 asfunc x y z = (some function pipeline built using x and y) z
Then I can cancel out the
z
s to getfunc 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
andt
go through:
- Apply
ord
to each of them- Add the results
- Subtract 2*a
- Take the result mod 26
- Add a
- 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 onmod
, and sections using-
get messy in Haskell so there's asubtract
function (they clash with the syntax for writing negative numbers:(-2)
means negative 2, and isn't the same assubtract 2
).In this function,
ord k + ord t
is an excellent candidate for usingData.Function.on
(link). This useful combinator lets us replaceord k + ord t
with a function applied tok
andt
: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屋!