2010-09-24 11 views
13

¿Existe una notación elegante para Currying los argumentos de una función fuera de servicio en Haskell?Currying out of order in Haskell

Por ejemplo, si desea dividir 2 por todos los elementos de una lista, puede escribir

map ((/) 2) [1,2,3,4,5] 

Sin embargo para dividir todos los elementos de una lista que parece es necesario definir una función anónima

map (\x -> x/2) [1,2,3,4,5] 

Las funciones anónimas se vuelven rápidamente difíciles de manejar en casos más complejos. Soy consciente de que en este caso el mapa ((*) 0.5) [1, 2, 3, 4, 5] funcionaría bien, pero me interesa saber si Haskell tiene una manera más elegante de resolver los argumentos de una función ¿fuera de servicio?

+0

'flip' y backticks son buenos junto con el simple uso de la función infijo (como señala Delnan). –

Respuesta

16

En este caso en particular:

Prelude> map (/2) [1..5] 
[0.5,1.0,1.5,2.0,2.5] 

No sólo se puede utilizar un operador infijo como función de prefijo común, también puede aplicar parcialmente en forma infija. Del mismo modo, el primer ejemplo sería mejor escribir como map (2/) [1..5]

Además, hay flip que no es tan elegante, pero sigue siendo la mejor opción disponible para las funciones normales (cuando no se desea convertirlos en infija a través de acentos abiertos) :

Prelude> let div' = (/) 
Prelude> div' 2 1 
2.0 
Prelude> flip div' 2 1 
0.5 
+0

¿Esto solo funciona con operadores? ¿Qué hay de las funciones arbitrarias? – Gabe

+0

@Gabe: como FUZxxl escribió, también funciona con funciones que se usan infix (rodeándolas con palos de atrás). Daría un ejemplo, pero él ya me dio uno. – delnan

+0

Gracias.Es una pena que no haya sintaxis como f 1 2 # 4 #, que tenga el mismo efecto que \ x y -> f 1 2 x 4 y. – hosiers

2

para su segundo, el lambda es innecesario, sólo tiene que utilizar como:

map (/2) [1..5] 

la forma (/ 2) simplemente significa, que desea acceder al segundo parámetro de un operador. También es posible con el primer argumento (2/). Esto se llama sección, y es un truco realmente útil, no solo en código de golf. También se puede utilizar en las funciones de prefijo, si se utilizan INFIX:

map (`div` 2) [1..5] 

En los casos más difíciles, como 3 o más argumentos, se supone que debes usar lambdas, ya que se hace más legibles mayoría de las veces.

2

Creo que está buscando una solución generalizada, como el cut en el esquema. ¿Derecha?

Existe la función flip que invierte los primeros 2 argumentos de una función. Puede haber otras funciones haciendo una tarea similar (no soy muy bueno en Haskell ... todavía).

+1

'flip' no invierte la lista de argumentos. Simplemente voltea los dos primeros, considere esto: 'flip (.) :: (a -> b) -> (b -> c) -> a -> c'. -1 – fuz

0

me encontré con un very similar issue yo recientemente, y yo no era capaz de encontrar una solución elegante con excepción de usar una función de ayuda para hacerlo:

dbfunc f b c = (\a -> liftIO $ f a b c) 
deleteAllRows = do 
    ask >>= dbfunc run "delete from t1" [] 

Al menos este patrón es bastante común en HDBC que dbfunc es reutilizable

+0

'ask >> = liftIO. (flip. (flip run) "eliminar de t1" []) ' – is7s

+0

Para ciertos valores de elegante ;-) – Gaius

Cuestiones relacionadas