在Haskell中没有点

Igo*_*gor 17 haskell coding-style pointfree

我有这个代码,我想做点无关;

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

我怎么做?

除了"想想这个和某些东西"之外,还有一些关于点自由风格的一般规则吗?

Nef*_*byr 52

转一个功能

func x y z = (some expression in x, y and z)
Run Code Online (Sandbox Code Playgroud)

对于无点形式,我通常会尝试按照对最后一个参数所做的操作z并将函数写为

func x y z = (some function pipeline built using x and y) z
Run Code Online (Sandbox Code Playgroud)

然后我可以取消zs得到

func x y = (some function pipeline built using x and y)
Run Code Online (Sandbox Code Playgroud)

然后重复y和x的过程应该func以无点形式结束.在这个过程中认识到的一个重要转变是:

    f z = foo $ bar z    -- or f z = foo (bar z)
<=> f z = foo . bar $ z
<=> f   = foo . bar
Run Code Online (Sandbox Code Playgroud)

同样重要的是要记住,通过部分评估,您可以"中断"函数的最后一个参数:

foo $ bar x y == foo . bar x $ y    -- foo applied to ((bar x) applied to y)
Run Code Online (Sandbox Code Playgroud)

为了您的特定功能,考虑到流动是kt经历:

  1. 适用ord于他们每个人
  2. 添加结果
  3. 减去2*a
  4. 取结果mod 26
  5. 添加一个
  6. 应用 chr

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

func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ord k + ord t
Run Code Online (Sandbox Code Playgroud)

请注意,你可以避免flip使用一节mod,并-在Haskell中使用get messy 的部分,所以有一个subtract函数(它们与编写负数的语法冲突:(-2)表示负2,并且不相同subtract 2).

在这个函数中,ord k + ord t是使用Data.Function.on(链接)的一个很好的候选者.这个有用的组合器让我们可以替换ord k + ord t为应用于的函数kt:

func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ((+) `on` ord) k t
Run Code Online (Sandbox Code Playgroud)

我们现在非常接近

func k t = (function pipeline) k t
Run Code Online (Sandbox Code Playgroud)

因此

func = (function pipeline)
Run Code Online (Sandbox Code Playgroud)

不幸的是,Haskell在用一系列一元函数组成二进制函数时有点乱,但有一个技巧(我会看看我是否可以找到一个很好的参考),我们最终得到:

import Data.Function (on)

func = ((chr . (+a) . (`mod` 26) . subtract (2*a)) .) . ((+) `on` ord)
Run Code Online (Sandbox Code Playgroud)

除了那个丑陋的构图技巧之外,这几乎是一个很好的简洁无点功能管道.通过定义本页.:评论中建议的运算符,这可以整理一下:

import Data.Function (on)

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

func = (chr . (+a) . (`mod` 26) . subtract (2*a)) .: ((+) `on` ord)
Run Code Online (Sandbox Code Playgroud)

为了更好地完善这一点,您可以添加一些辅助函数来将字母< - > Int转换与Caesar密码算术分开.例如:letterToInt = subtract a . ord


sep*_*p2k 10

除了"想想这个和某些东西"之外,还有一些关于点自由风格的一般规则吗?

你总是可以欺骗并使用lambdabot中的"​​pl"工具(通过freenode上的#haskell或者使用例如酸的ghci).对于你的代码pl给出:

((chr . (a +) . flip mod 26) .) . flip flip (2 * a) . ((-) .) . (. ord) . (+) . ord

如果你问我,这不是一个真正的改进.

  • 这就是为什么"pl"是无意义的,而不是无点的:) (7认同)