2010-12-29 4 views
32

¿Hay alguna manera en Haskell de enlazar el segundo argumento pero no el primero de una función sin usar funciones lambda o definir otra función "local"?¿Cómo puedo vincular el segundo argumento en una función pero no en la primera (de una manera elegante)?

Ejemplo. Tengo una función binaria como:

sub :: Int -> Int -> Int 
sub x y = x - y 

Ahora si quiero enlazar el primer argumento, que puede hacerlo fácilmente usando (someExpression sub):

mapSubFrom5 x = map (sub 5) x 

*Main> mapSubFrom5 [1,2,3,4,5] 
[4,3,2,1,0] 

Eso funciona bien si quiero unir los primeros n argumentos sin "gap".

Si quiero enlazar el segundo argumento, pero no el primero, las dos opciones que conozco son más detallado:

O a través de otro, local, función:

mapSub5 x = map sub5 x 
    where sub5 x = sub x 5 

*Main> mapSub5 [1,2,3,4,5] 
[-4,-3,-2,-1,0] 

O usando lambda :

mapSub5 x = map (\x -> sub x 5) x 

Mientras que ambos están trabajando muy bien, me gusta la elegancia del "sub 5" y se preguntan si hay una manera elegante de manera similar a obligar a la enésima (n> 1) argumento de una función?

Respuesta

28

flip, que produce una nueva función con los dos primeros argumentos invertida, ya ha sido mencionado como una solución straigtforward.

Sin embargo, vale la pena señalar que Haskell define una buena sintaxis de infijo para los operadores binarios.

En primer lugar, es simplemente

sub = (-) 

Con paréntesis alrededor, todos los operadores son - syntactially también - funciones ordinarias. Ahora podemos curry operadores con alguna sintaxis especial. La unión al primer operando:

addOne = (1 +) 

... y al segundo

half = (/ 2) 

De este modo se convierte en el código de

map (-5) [1..5] 

Desafortunadamente, -5 es un número literal, sino que presentamos lo mejor punto.:) Ahora ya podemos convertir cualquier función en un operador binario poniendo acentos abiertos a su alrededor como en

f x y == x `f` y 

podemos utilizar esta sintaxis especial operador escriba

map (`sub` 5) [1..5] 


Nota: currying el primer argumento es común, el segundo, como en su caso, es muy posible. Pero: no haría eso por otros argumentos. Las funciones de Haskell están escritas en un estilo que los comunes para curry están en el frente exactamente por esa razón.

Usar una sintaxis especial para argumentos adicionales parece demasiado implícito para mí. Simplemente use la lambda y déle a las variables nombres descriptivos.

+12

Como '-5' es un número, los fabricantes de haskell incluso agregaron una función de 'restar' que se define como' restar = voltear (-) 'para que pueda escribir' mapa (restar 5) '. Sin embargo, es más legible. – fuz

+3

Además, un corolario de la nota final: si a menudo desea aplicar parcialmente argumentos posteriores a una función que usted mismo escribió, ¡no dude en cambiar el orden directamente! Es relativamente raro que una función tenga tres o más argumentos que es probable que se usen de esa manera. –

7

Cómo enlazar el segundo argumento:

div2 = flip div 2 

ghci> div2 10 
5 

En su caso se puede escribir

ghci> map (flip (-) 5) [1..5] 
[-4,-3,-2,-1,0] 

Tenga en cuenta que en Haskell se puede escribir en forma de prefijo operadores como (-). Es lo mismo que sub en su pregunta.

+0

(Sé que (-). Sub era solo una función de ejemplo primitivo) Gracias por señalar para voltear. Eso funciona al menos para el caso del segundo argumento. Aunque creo que las formas más detalladas donde/lambda son más legibles. –

8

Para n = 2 sólo otro modo de obligar:

mapSub5 x = map (`sub` 5) x 
Cuestiones relacionadas