f# - etiqueta - title en seo
FunciĆ³n F#llamando a la confusiĆ³n de sintaxis (3)
Tengo un código:
links
|> Seq.map (fun x -> x.GetAttributeValue ("href", "no url"))
A la que quería reescribir:
links
|> Seq.map (fun x -> (x.GetAttributeValue "href" "no url"))
Pero al compilador de F # no parece gustarle eso. Tenía la impresión de que estas dos llamadas a funciones eran intercambiables:
f (a, b)
(f a b)
El error que me sale es:
El miembro o el constructor de objetos ''GetAttributeValue'' que toma 2 argumentos no son accesibles desde esta ubicación de código. Todas las versiones accesibles del método ''GetAttributeValue'' toman 2 argumentos.
Lo que parece divertido, ya que parece indicar que necesita lo que le estoy dando. ¿Que me estoy perdiendo aqui?
En f (a,b)
, f
debe ser una función que tome un solo argumento (que es un par).
En fab
, que es la abreviatura de (fa) b
, f
cuando se aplica a a
devuelve una función que se aplica a b
.
Ambas son formas casi equivalentes de pasar argumentos a una función, pero no puede usar una función diseñada para un estilo con el otro. El segundo estilo se llama " currying ". Tiene la ventaja de permitir que se realicen algunos cálculos tan pronto como se pasa a, especialmente si va a utilizar el mismo a
con diferentes b
s. En este caso puedes escribir:
let f_a = f a (* computations happen now that a is available *)
in
f_a b1 .... f_a b2 ....
Para responder a su pregunta implícita, en este tipo de situación, puede ser útil escribir una pequeña función auxiliar:
let getAttrVal (x:TypeOfX) key default = x.GetAttributeValue(key, default)
//usage
links |> Seq.map (fun x -> getAttrVal x "href", "no url"))
y dependiendo de cómo quieras usarlo, podría ser más útil hacerlo "al revés":
let getAttrVal key default (x:TypeOfX) = x.GetAttributeValue(key, default)
//partial application
let getHRef = getAttrVal "href" "no url"
//usage
links |> Seq.map (fun x -> getHRef x)
//or, same thing:
links |> Seq.map getHRef
Una llamada de función habitual en F # se escribe sin paréntesis y los parámetros están separados por espacios. La forma simple de definir una función de varios parámetros es escribir esto:
let add a b = a + b
Como señaló Pascal, esta forma de especificar parámetros se llama currying: la idea es que una función toma solo un único parámetro y el resultado es una función que toma el segundo parámetro y devuelve el resultado real (u otra función). Al llamar a una función simple como esta, escribiría add 10 5
y el compilador (en principio) lo interpreta como ((add 10) 5)
. Esto tiene algunas ventajas interesantes, por ejemplo, le permite usar la aplicación de función parcial en la que especifica solo los primeros argumentos de una función:
let addTen = add 10 // declares function that adds 10 to any argument
addTen 5 // returns 15
addTen 9 // returns 19
Esta característica es prácticamente útil, por ejemplo, al procesar listas:
// The code using explicit lambda functions..
[ 1 .. 10 ] |> List.map (fun x -> add 10 x)
// Can be rewritten using partial function application:
[ 1 .. 10 ] |> List.map (add 10)
Ahora, vamos a la parte confusa: en F #, también puede trabajar con tuplas, que son tipos de datos simples que le permiten agrupar varios valores en un solo valor (tenga en cuenta que las tuplas no están relacionadas de ninguna manera con las funciones). Puedes por ejemplo escribir:
let tup = (10, "ten") // creating a tuple
let (n, s) = tup // extracting elements of a tuple using pattern
printfn "n=%d s=%s" n s // prints "n=10 s=ten"
Cuando escribes una función que toma parámetros en paréntesis separados por una coma, en realidad estás escribiendo una función que toma un solo parámetro que es una tupla:
// The following function:
let add (a, b) = a * b
// ...means exactly the same thing as:
let add tup =
let (a, b) = tup // extract elements of a tuple
a * b
// You can call the function by creating tuple inline:
add (10, 5)
// .. or by creating tuple in advance
let t = (10, 5)
add t
Esta es una función de un tipo diferente: toma un solo parámetro que es una tupla, mientras que la primera versión fue una función que tomó dos parámetros (usando curry).
En F #, la situación es un poco más complicada que eso: los métodos .NET aparecen como métodos que toman una tupla como parámetro (por lo que puede llamarlos con la notación entre paréntesis), pero son algo limitados (por ejemplo, no puede crear una tupla primero y luego llame al método dándole solo la tupla). Además, el código F # compilado en realidad no produce métodos en forma de curry (por lo que no puede usar la aplicación de función parcial directamente desde C #). Esto se debe a razones de rendimiento: la mayoría de las veces, especifica todos los argumentos y esto se puede implementar de manera más eficiente.
Sin embargo, el principio es que una función toma múltiples parámetros o toma una tupla como parámetro.