2010-07-07 11 views
7

Aquí es código que funciona bien:¿Es posible en F # curry un argumento de función central?

let f x y z = x + y + z 

let g x y = f x y 
let h x z = z |> f x 

Por lo tanto, se puede escribir la expresión "h1", y muestra FSI:

val it : (int -> int -> int) = <fun:[email protected]> 

Si llamo "h 1 2 3", se aplican los argumentos en el orden correcto.
Pero si el último argumento tiene un tipo diferente, las cosas se ponen diferentes:

let ff x y (z : string) = x + y 

let gg x y = ff x y 
let hh x (z : string) = z |> ff x 

Ahora la última hh función hace que un mensaje de error:

Script.fsx (119,10): FS0001 de error : No coincide con el tipo Esperando un string -> 'a pero dado un int -> string -> int. El tipo string no coincide con el tipo int

entiendo por qué sucede esto - "z" se añade al "ff x" por lo que es un segundo argumento. Pero entonces esperaría que la primera expresión de ejemplo "h 1 2 3" no funcione correctamente (se ejecute como "f 1 3 2"). Pero funciona bien.

+1

¿Seguro que 'h 1 2 3' se ejecuta como' f 1 2 3' y no 'f 1 3 2'? Después de todo, 1 + 2 + 3 == 1 + 3 + 2 == 6. ¿Tal vez intentar con un operador no transitivo? – tzaman

+0

FWIW, los argumentos etiquetados de OCaml le permiten aplicar parcialmente fuera de servicio. –

Respuesta

8

Las funciones ff y gg en su ejemplo son los mismos - el operador de la canalización proporciona un valor para un primer argumento de una función en el lado derecho. En su ejemplo, la función en el lado derecho es ff x y utilizando el operador de la canalización, se especifica el valor para el argumento y:

let ff x y (z : string) = 
    printfn "%s" z 
    x + y 

// These two functions are the same: 
let gg x y = ff x y 
let hh x y = y |> ff x 

No hay sintaxis stnadard para especificar que no sean primeros parámetros cuando se utiliza la función parcial solicitud. Sin embargo, puede escribir una función de orden superior o un operador personalizado para hacer eso. Por ejemplo:

// Takes a function 'f' of type 'b -> 'a -> 'c 
// and a value 'v' of type 'a and creates a function 
// that takes the first argument ('b -> 'c) 
let (|*>) v f = (fun mid -> f mid v);; 

let gg x y = ff x y  // Specifies arguments x and y 
let hh x z = z |*> ff x // Specifies arguments x and z 

puse el nombre del operador |*> para denotar que se salta un argumento. Puede definir operadores que especifiquen el valor de otros argumentos de manera similar (por ejemplo, |**> para omitir los primeros dos argumentos).

+0

Tomás, gracias por la respuesta. ¡El uso del operador personalizado parece ser un camino por recorrer! –

+1

Creo que tienes los argumentos hacia atrás en ese operador. Creo que debería ser (última diversión -> f v último). Además, la aplicación de función tiene prioridad sobre los operadores, por lo que la última línea debería ser: (z | *> ff) x Intente probar esto con sustracción o división, en lugar de sumar. – YotaXP

+0

@YotaXP: Ambas cosas que mencionas son intencionales. Si escribiste al operador de la manera que describes (ej. 'Fun last -> fv last') no necesitarías la función lambda, porque eso sería equivalente a' fv' - que sería el operador '|>' estándar . En cuanto al segundo punto, la intención es que cuando escriba 'z | *> ff x', especifique' z' como el segundo argumento de una función 'ff x' (y el primer argumento queda por especificar). En otras palabras, 'z | *> ff x' es equivalente a' fun a -> ff x a z'. –

Cuestiones relacionadas