Pour activer une fonction
func x y z = (some expression in x, y and z)
en forme de point libre, j'essaie généralement de suivre ce qui se fait au dernier paramètre z
et écrire la fonction comme
func x y z = (some function pipeline built using x and y) z
Ensuite, je peux annuler sur les z
s pour obtenir
func x y = (some function pipeline built using x and y)
Puis répéter g le processus pour y et x devrait se terminer par func
sous forme sans point.Une transformation essentielle pour reconnaître dans ce processus est le suivant:
f z = foo $ bar z -- or f z = foo (bar z)
<=> f z = foo . bar $ z
<=> f = foo . bar
Il est également important de se rappeler que l'évaluation partielle, vous pouvez « casser » le dernier argument à une fonction:
foo $ bar x y == foo . bar x $ y -- foo applied to ((bar x) applied to y)
Pour votre particulier fonction, tenez compte des flux qui k
et t
passent par:
- Appliquer
ord
à chacun d'eux
- Ajouter les résultats
- Soustraire 2 * a
- Prenez le résultat mod 26
- Ajouter un
- Appliquer
chr
donc comme une première tentative de simplification, nous obtenons:
func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ord k + ord t
Notez que vous pouvez éviter flip
en utilisant une section sur mod
, et les sections utilisant -
sont désordonnées dans Haskell, donc il y a une fonction subtract
(elles se heurtent à la syntaxe pour écrire des nombres négatifs: (-2)
signifie négatif 2, et n'est pas la même chose que subtract 2
). Dans cette fonction, ord k + ord t
est un excellent candidat pour utiliser Data.Function.on
(link). Ce combinateur utile nous permet de remplacer ord k + ord t
avec une fonction appliquée à k
et t
:
func k t = chr . (+a) . (`mod` 26) . subtract (2*a) $ ((+) `on` ord) k t
Nous sommes maintenant très près d'avoir
func k t = (function pipeline) k t
et donc
func = (function pipeline)
Malheureusement Haskell est un peu brouillon quand il s'agit de composer une fonction binaire avec une séquence de fonctions unaires, mais il y a un truc (je verrai si je peux trouver un bonne référence pour elle), et nous nous retrouvons avec:
import Data.Function (on)
func = ((chr . (+a) . (`mod` 26) . subtract (2*a)) .) . ((+) `on` ord)
qui est presque une belle conduite de fonction de point sans propre, sauf pour ce truc de composition laid. En définissant l'opérateur .:
suggéré dans les commentaires on this page, ce tidies un peu à:
import Data.Function (on)
(.:) = (.).(.)
func = (chr . (+a) . (`mod` 26) . subtract (2*a)) .: ((+) `on` ord)
Pour polir ce un peu plus, vous pouvez ajouter des fonctions d'aide à séparer la lettre < -> conversion Int de la Caesar cipher arithmétique . Par exemple: letterToInt = subtract a . ord
Pourquoi voudriez-vous rendre ce point-gratuit? – yfeldblum
Parce que pouvoir écrire du code sans point ressemble à l'une des propriétés d'un bon programmeur Haskell. – Igor
Parfois, le code sans point est plus clair que son alternative non-ponctuelle, et c'est une bonne idée d'utiliser un style sans point. Ce n'est pas un de ces temps. – dave4420