Si vous vous sentez comme des fonctions d'édition après qu'ils sont écrits, vous devriez vraiment vraiment lire Conal Elliott excellent éditeur sémantique blog combinators
http://conal.net/blog/posts/semantic-editor-combinators
En fait, tout le monde devrait lire de toute façon. C'est une méthode vraiment utile (que j'abuse ici). Conal utilise plus de constructions que juste result
et flip
pour un effet très flexible.
result :: (b -> b') -> ((a -> b) -> (a -> b'))
result = (.)
Supposons que j'ai une fonction qui utilise 3 arguments
use3 :: Char -> Double -> Int -> String
use3 c d i = c: show (d^i)
et je voudrais échanger les deux premiers, je venais d'utiliser flip use3
comme vous le dites, mais si je voulais échanger le deuxième et le troisième, ce que je veux est d'appliquer flip
au résultat de l'application use3
à son premier argument.
use3' :: Char -> Int -> Double -> String
use3' = (result) flip use3
déménagement Let le long et échanger les quatrième et cinquième arguments d'une fonction use5
qui utilise 5.
use5 :: Char -> Double -> Int -> (Int,Char) -> String -> String
use5' :: Char -> Double -> Int -> String -> (Int,Char) -> String
use5 c d i (n,c') s = c : show (d^i) ++ replicate n c' ++ s
Nous devons appliquer flip
au résultat de l'application use5
à ses trois premiers arguments, donc c'est le résultat du résultat du résultat:
use5' = (result.result.result) flip use5
Pourquoi ne pas penser plus tard et définir
swap_1_2 :: (a1 -> a2 -> other) -> (a2 -> a1 -> other)
swap_2_3 :: (a1 -> a2 -> a3 -> other) -> (a1 -> a3 -> a2 -> other)
--skip a few type signatures and daydream about scrap-your-boilerplate and Template Haskell
swap_1_2 = flip
swap_2_3 = result flip
swap_3_4 = (result.result) flip
swap_4_5 = (result.result.result) flip
swap_5_6 = (result.result.result.result) flip
... et c'est là que vous devriez vous arrêter si vous aimez la simplicité et l'élégance. Notez que le type other
pourrait être b -> c -> d
donc en raison de fabuleux Curry et associativité droite de ->
, swap_2_3 fonctionne pour une fonction qui prend n'importe quel nombre d'arguments au-dessus de deux. Pour quelque chose de plus compliqué, vous devriez vraiment écrire une fonction permutée à la main. Ce qui suit est juste pour la curiosité intellectuelle.
Maintenant, qu'en est-il de l'échange des deuxième et quatrième arguments? [En plus: il y a un théorème Je me souviens de mes cours d'algèbre que toute permutation peut être faite que la composition de la permutation des éléments adjacents.]
On pourrait le faire comme ceci: étape 1: déplacer 2 à côté de 4 (swap_2_3
)
a1 -> a2 -> a3 -> a4 -> otherstuff
a1 -> a3 -> a2 -> a4 -> otherstuff
les échanger en utilisant là swap_3_4
a1 -> a3 -> a2 -> a4 -> otherstuff
a1 -> a3 -> a4 -> a2 -> otherstuff
puis échanger 4 en position 2 en utilisant à nouveau swap_2_3
:
a1 -> a3 -> a4 -> a2 -> otherstuff
a1 -> a4 -> a3 -> a2 -> otherstuff
si
swap_2_4 = swap_2_3.swap_3_4.swap_2_3
Peut-être qu'il ya une façon plus laconique d'y arriver directement avec beaucoup de résultats et flips mais Messing aléatoire n'a pas trouvé pour moi!
De même, pour échanger 1 et 5, nous pouvons déplacer 1 sur 4, swap avec 5, 5 déplacer en arrière de 4 à 1.
swap_1_5 = swap_1_2.swap_2_3.swap_3_4 . swap_4_5 . swap_3_4.swap_2_3.swap_1_2
Ou si vous préférez vous pourriez réutiliser swap_2_4
en retournant à la termine (permutation 1 avec 2 et 5 avec 4), swap_2_4 puis retour aux extrémités.
swap_1_5' = swap_1_2.swap_4_5. swap_2_4 .swap_4_5.swap_1_2
Bien sûr, il est beaucoup plus facile de définir
swap_1_5'' f a b c d e = f e b c d a
qui a l'avantage d'être clair, concise, efficace et a une signature de type utile dans ghci sans explicitement annotant.
Cependant, c'était une question très amusante, merci.
@phimuemue il peut ne pas être une fonction, mais des macros TH. Oui, une telle macro peut être écrite, mais le lambda simple est presque aussi court. – permeakra
Si vous avez tendance à avoir beaucoup d'arguments, vous risquez de manquer des opportunités de créer des types de données appropriés. Ou vous êtes juste une personne querelleuse. – Landei