f# - .net programming language
¿Qué significa-> en F#? (9)
''->'' no es un operador. Aparece en la sintaxis F # en varios lugares, y su significado depende de cómo se usa como parte de una construcción más grande.
Dentro de un tipo, ''->'' describe los tipos de funciones como las personas han descrito anteriormente. Por ejemplo
let f : int -> int = ...
dice que ''f'' es una función que toma un int y devuelve un int.
Dentro de una lambda ("cosa que comienza con la palabra clave ''divertida''"), ''->'' es la sintaxis que separa los argumentos del cuerpo. Por ejemplo
fun x y -> x + y + 1
es una expresión que define una función de dos argumentos con la implementación dada.
Dentro de una construcción de "coincidencia", ''->'' es la sintaxis que separa los patrones del código que debería ejecutarse si el patrón se corresponde. Por ejemplo, en
match someList with
| [] -> 0
| h::t -> 1
lo que está a la izquierda de cada ''->'' son patrones, y lo que está a la derecha es lo que sucede si el patrón de la izquierda coincide.
La dificultad de comprensión puede estar arraigada en la suposición errónea de que ''->'' es "un operador" con un único significado. Una analogía podría ser "." en C #, si nunca antes ha visto ningún código, y trate de analizar el "." operador basado en mirar "Obj.Method" y "3.14" y "System.Collections", puede confundirse mucho, porque el símbolo tiene diferentes significados en diferentes contextos. Sin embargo, una vez que sabes lo suficiente del idioma para reconocer estos contextos, las cosas se vuelven claras.
Estuve intentando entrar y salir de F # por un tiempo, pero sigo desilusionándome. ¿Por qué?
Porque no importa qué recurso de ''principiantes'' trato de ver, veo ejemplos muy simples que comienzan a usar el operador ->
.
Sin embargo, en ninguna parte he encontrado hasta ahora que proporcione una explicación clara y simple de lo que significa este operador. Es como si fuera tan obvio que no necesita explicación ni para completar a los novatos.
Por lo tanto, debo ser muy denso o tal vez son casi 3 décadas de experiencia previa que me detienen.
¿Puede alguien por favor, explicarlo o señalar a un recurso verdaderamente accesible que lo explique?
(a -> b) significa "función de a a b". En la anotación de tipo, denota un tipo de función. Por ejemplo, f: (int -> String) significa que f se refiere a una función que toma un entero y devuelve una cadena. También se usa como un consttructor de tales valores, como en
val f : (int -> int) = fun n -> n * 2
que crea un valor que es una función de un número n a ese mismo número multiplicado por dos.
Básicamente significa "mapas para". Léelo de esa manera o como "se transforma en" o algo así.
Entonces, desde el F # en 20 minutos de tutorial,
> List.map (fun x -> x % 2 = 0) [1 .. 10];;
val it : bool list
= [false; true; false; true; false; true; false; true; false; true]
El código (funcion i -> i% 2 = 0) define una función anónima, llamada expresión lambda, que tiene un parámetro x y la función devuelve el resultado de "x% 2 = 0", que es si x es o no incluso.
De Microsoft :
Los tipos de funciones son los tipos dados a los valores de función de primera clase y se escriben int -> int. Son similares a los tipos de delegados .NET, excepto que no reciben nombres. Todos los identificadores de función F # se pueden usar como valores de función de primera clase, y los valores de función anónimos se pueden crear utilizando el formulario de expresión (diversión ... -> ...).
Lo bueno de los lenguajes como Haskell (es muy similar en F #, pero no sé la sintaxis exacta - esto debería ayudarte a entender ->, sin embargo) es que puedes aplicar solo partes del argumento, para crear curried funciones:
adder n x y = n + x + y
En otras palabras: "dame tres cosas, y las agregaré juntas". Cuando le arrojas números, el compilador inferirá los tipos de nx e y. Digamos que escribes
adder 1 2 3
El tipo de 1, 2 y 3 es Int. Por lo tanto:
adder :: Int -> Int -> Int -> Int
Es decir, dame tres enteros, y me convertiré en un entero, finalmente, o lo mismo que decir:
five :: Int
five = 5
Pero, esta es la parte buena! Prueba esto:
add5 = adder 5
Como recordará, adder toma un int, un int, un int, y le devuelve un int. Sin embargo, esa no es toda la verdad, como verá pronto. De hecho, add5 tendrá este tipo:
add5 :: Int -> Int -> Int
Será como si se hubiera "desprendido" de los enteros (el más a la izquierda) y se hubiera pegado directamente a la función. Mirando más de cerca la firma de la función, notamos que los -> son asociativos correctos, es decir:
addder :: Int -> (Int -> (Int -> Int))
Esto debería dejarlo bastante claro: cuando le das al sumador el primer entero, lo evaluará a lo que esté a la derecha de la primera flecha, o:
add5andtwomore :: Int -> (Int -> Int)
add5andtwomore = adder 5
Ahora puede usar add5andtwomore en lugar de "sumador 5". De esta forma, puede aplicar otro entero para obtener (digamos) "add5and7andonemore":
add5and7andonemore :: Int -> Int
add5and7andonemore = adder 5 7
Como puede ver, agregue5y7yuno quiere exactamente otro argumento, y cuando le dé uno, de repente se convertirá en un número entero.
> add5and7andonemore 9
=> ((add5andtwomore) 7) 9
=> ((adder 5) 7) 9)
<=> adder 5 7 9
Sustituyendo los parámetros por sumador (nxy) por (5 7 9), obtenemos:
> adder 5 7 9 = 5 + 7 + 9
=> 5 + 7 + 9
=> 21
De hecho , plus también es solo una función que toma un int y te devuelve otro int, por lo que lo anterior es más como:
> 5 + 7 + 9
=> (+ 5 (+ 7 9))
=> (+ 5 16)
=> 21
¡Aquí tienes!
Ya hay muchas respuestas excelentes, solo quiero agregar a la conversación otra forma de pensar al respecto.
''->'' significa función.
''a ->'' b es una función que toma una ''a y devuelve una'' b
(''a *'' b) -> (''c *'' d) es una función que toma una tupla de tipo (''a,'' b) y devuelve una tupla de (''c,'' d). Tal como int / string devuelve float / char.
Donde se pone interesante es en el caso de cascada de ''a ->'' b -> ''c. Esta es una función que toma ''a y devuelve una función ('' b -> ''c), o una función que toma'' b -> ''c.
Entonces, si escribes: deja que fxyz = ()
El tipo será f: ''a ->'' b -> ''c -> unidad, por lo que si solo se aplica el primer parámetro, el resultado sería una función curried'' b -> ''c ->'' unidad.
Muchas excelentes respuestas a estas preguntas, gracias a la gente. Me gustaría poner aquí una respuesta editable que reúna las cosas.
Para aquellos familiarizados con la comprensión de C # -> siendo lo mismo que => la expresión de lamba es un buen primer paso. Este uso es:
fun x y -> x + y + 1
Puede ser entendido como el equivalente a: -
(x, y) => x + y + 1;
Sin embargo, es claro que -> tiene un significado más fundamental que deriva del concepto de que una función que toma dos parámetros como el anterior se puede reducir (¿es ese el término correcto?) A una serie de funciones que solo toman un parámetro.
Por lo tanto, cuando lo anterior se describe de esta manera:
Int -> Int -> Int
Realmente ayudó a saber que -> es correcto asociativo por lo tanto, se puede considerar lo anterior: -
Int -> (Int -> Int)
Aha! Tenemos una función que toma Int y devuelve (Int -> Int) (¿una función curried?).
La explicación de que -> también puede aparecer como parte de la definición de tipo también ayudó. (Int -> Int) es el tipo de cualquiera de las funciones que toma un Int y devuelve un Int.
También es útil que -> aparezca en otra sintaxis, como la coincidencia, pero ¿no tiene el mismo significado? ¿Es eso correcto? No estoy seguro de que sea así. Sospecho que tiene el mismo significado, pero aún no tengo el vocabulario para expresarlo.
Tenga en cuenta que el objetivo de esta respuesta no es generar más respuestas, sino que las personas las editen colaborativamente para crear una respuesta más definitiva. En última instancia, sería bueno que se eliminen todas las incertidumbres y fluidez (como este párrafo) y se añadan mejores ejemplos. Intentemos mantener esta respuesta lo más accesible posible para los no iniciados.
En el contexto de la definición de una función, es similar a =>
partir de la expresión lambda en C # 3.0.
F#: let f = fun x -> x*x
C#: Func<int, int> f = x => x * x;
El ->
in F # también se utiliza en la coincidencia de patrones, donde significa: si la expresión coincide con la parte entre |
y ->
, entonces lo que viene después ->
debe devolverse como resultado:
let isOne x = match x with
| 1 -> true
| _ -> false
Primera pregunta: ¿estás familiarizado con las expresiones lambda en C #? Si es así, el -> en F # es igual que el => en C # (creo que lo lees ''va a'').
El operador -> también se puede encontrar en el contexto de la coincidencia de patrones
match x with
| 1 -> dosomething
| _ -> dosomethingelse
No estoy seguro si esto también es una expresión lambda, o algo más, pero creo que el ''va a'' todavía se mantiene.
Tal vez a lo que realmente se refiere es a las respuestas "crípticas" del analizador F #:
> let add a b = a + b
val add: int -> int -> int
Esto significa (como la mayoría de los ejemplos lo explican) que add es un ''val'' que toma dos ints y devuelve un int. Para mí, esto fue totalmente opaco para empezar. Quiero decir, ¿cómo sé que add no es un val que toma una int y devuelve dos ints?
Bueno, la cosa es que, en cierto sentido, sí. Si doy solo agregue una int, obtengo un (int -> int):
> let inc = add 1
val inc: int -> int
Esto (currying) es una de las cosas que hace F # tan sexy, para mí.
Para obtener información útil sobre F #, he encontrado que los blogs son MUCHO más útiles que cualquiera de la ''documentación'' oficial: aquí hay algunos nombres para consultar
- Dustin Campbell (eso es diditwith.net, citado en otra respuesta)
- Don Symes (''el'' hombre)
- Tomasp.net (también conocido como Tomas Petricek )
- Andrew Kennedy (para unidades de medida)
- Fsharp.it (famoso por las soluciones Project Euler)
- http://lorgonblog.spaces.live.com/Blog (aka Brian )
- Jomo Fisher