Si usted se siente como funciones de edición después de ser escritos, que realmente realmente debe leer el excelente blog de Conal Elliott combinadores editor semánticas
http://conal.net/blog/posts/semantic-editor-combinators
De hecho, todo el mundo debería leer todos modos. Es un método genuinamente útil (que estoy abusando aquí). Conal utiliza más constructos que solo result
y flip
con un efecto muy flexible.
result :: (b -> b') -> ((a -> b) -> (a -> b'))
result = (.)
Supongamos que tengo una función que utiliza 3 argumentos
use3 :: Char -> Double -> Int -> String
use3 c d i = c: show (d^i)
y me gustaría intercambiar los dos primeros, que acababa de uso flip use3
como usted dice, pero si quería intercambie el segundo y tercero, lo que quiero es aplicar flip
al resultado de aplicar use3
a su primer argumento. movimiento
use3' :: Char -> Int -> Double -> String
use3' = (result) flip use3
Vamos a lo largo y cambiar los argumentos cuarto y quinto de una función use5
que utiliza 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
Necesitamos aplicar flip
al resultado de aplicar use5
a sus primeros tres argumentos, así que ese es el resultado del resultado del resultado:
use5' = (result.result.result) flip use5
¿Por qué no guardar el pensamiento después? y define
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
... y ahí es donde deberías parar si te gusta la simplicidad y la elegancia. Tenga en cuenta que el tipo other
podría ser b -> c -> d
por lo que debido al fabuloso Curry y asociatividad correcta de ->
, swap_2_3 funciona para una función que toma cualquier número de argumentos por encima de dos. Para algo más complicado, realmente debe escribir una función permutada a mano. Lo que sigue es solo por el bien de la curiosidad intelectual.
Ahora, ¿qué hay de intercambiar los argumentos segundo y cuarto? [Aparte: hay un teorema que recuerdo de mis conferencias de la álgebra que cualquier permutación se puede hacer como la composición de intercambio de elementos adyacentes.]
podríamos hacerlo así: paso 1: mover 2 junto a 4 (swap_2_3
)
a1 -> a2 -> a3 -> a4 -> otherstuff
a1 -> a3 -> a2 -> a4 -> otherstuff
ellos intercambie allí utilizando swap_3_4
a1 -> a3 -> a2 -> a4 -> otherstuff
a1 -> a3 -> a4 -> a2 -> otherstuff
entonces intercambiar 4 de vuelta a la posición 2 usando swap_2_3
nuevo:
a1 -> a3 -> a4 -> a2 -> otherstuff
a1 -> a4 -> a3 -> a2 -> otherstuff
por lo
swap_2_4 = swap_2_3.swap_3_4.swap_2_3
Tal vez hay una manera más concisa de llegar allí directamente con un montón de resultados y voltea Y jugando al azar, no lo encontró para mí!
Del mismo modo, para intercambiar 1 y 5 se puede mover 1 a 4, intercambio con 5, 5 mover hacia atrás de 4 a 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
O si lo prefiere, puede volver a utilizar swap_2_4
moviendo de un tirón en el termina (intercambiando 1 con 2 y 5 con 4), swap_2_4 y volteando nuevamente en los extremos.
swap_1_5' = swap_1_2.swap_4_5. swap_2_4 .swap_4_5.swap_1_2
Por supuesto que es mucho más fácil definir
swap_1_5'' f a b c d e = f e b c d a
que tiene la ventaja de ser claro, conciso, eficiente y tiene una firma de tipo útiles en ghci sin anotar explícitamente él.
Sin embargo, esta fue una pregunta fantásticamente entretenida, gracias.
@phimuemue puede que no sea una función, sino macros TH. Sí, se puede escribir dicha macro, pero la lambda simple es casi tan corta. – permeakra
Si tiende a tener muchos argumentos, puede perder oportunidades de crear tipos de datos apropiados. O solo eres una persona quejumbrosa. – Landei