Чтобы включить функцию
func x y z = (some expression in x, y and z)
в виде без точек, я обычно стараюсь следить за тем, что делается с последним параметром z
и пишу функцию как
func x y z = (some function pipeline built using x and y) z
Тогда я могу отменить z
s, чтобы получить
func x y = (some function pipeline built using x and y)
Тогда повторение процесса для y и x должно закончиться с func
в бессмысленной форме. Существенная трансформация для распознавания в этом процессе:
f z = foo $ bar z -- or f z = foo (bar z)
<=> f z = foo . bar $ z
<=> f = foo . bar
Также важно помнить, что при частичной оценке вы можете «обрывать» последний аргумент функции:
foo $ bar x y == foo . bar x $ y -- foo applied to ((bar x) applied to y)
Для вашей конкретной функции рассмотрим поток, через который проходят k
и t
:
- Применить
ord
к каждому из них
- Добавить результаты
- Вычесть 2 * а
- Возьми результат мод 26
- Добавить
- Применить
chr
Итак, в качестве первой попытки упрощения мы получаем:
func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ord k + ord t
Обратите внимание, что вы можете избежать flip
, используя раздел в mod
, а разделы, использующие -
, запутаются в Haskell, поэтому есть функция subtract
(они конфликтуют с синтаксисом для записи отрицательных чисел: * 1046) * означает минус 2 и не совпадает с subtract 2
).
В этой функции ord k + ord t
является отличным кандидатом для использования Data.Function.on
( link ). Этот полезный комбинатор позволяет нам заменить ord k + ord t
функцией, примененной к k
и t
:
func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ((+) `on` ord) k t
Мы сейчас очень близки к тому, чтобы
func k t = (function pipeline) k t
и, следовательно,
func = (function pipeline)
К сожалению, Haskell немного запутан, когда дело доходит до составления бинарной функции с последовательностью унарных функций, но есть хитрость (я посмотрю, смогу ли я найти хорошую ссылку на нее), и мы в итоге получим :
import Data.Function (on)
func = ((chr . (+a) . (`mod` 26) . subtract (2*a)) .) . ((+) `on` ord)
, который является почти хорошим аккуратным конвейером функций без точек, за исключением этого уродливого трюка. Определяя оператор .:
, предложенный в комментариях на этой странице , это немного прибавляет:
import Data.Function (on)
(.:) = (.).(.)
func = (chr . (+a) . (`mod` 26) . subtract (2*a)) .: ((+) `on` ord)
Чтобы отточить это, вы можете добавить некоторые вспомогательные функции, чтобы отделить преобразование буквы <-> Int от шифра Цезаря . Например: letterToInt = subtract a . ord