2008-09-19 19 views
23

He intentado entrar y salir de F # por un tiempo, pero sigo desilusionándome. ¿Por qué?¿Qué significa -> en F #?

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 explicarlo o señalar a un recurso verdaderamente accesible que lo explique?

+0

Todo parece realmente griego para mí también. – Brettski

+0

Solo llámalo Matusalén. –

+0

En realidad, Matusalén vivió durante 969 años, así que todavía tendría un tercio de su edad. Sin embargo, gracias editadas;) – AnthonyWJones

Respuesta

46

'->' 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 que 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 'fun'"), '->' 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 coincide. Por ejemplo, en

match someList with 
| [] -> 0 
| h::t -> 1 

la materia a la izquierda de cada '->' son patrones, y las cosas de la derecha es lo que sucede si se correspondía con el patrón de la izquierda.

La dificultad en la comprensión puede estar enraizada 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.

+0

He aceptado esto como la respuesta porque es el armario a la clase de respuesta completa que estaba buscando pero hay hay otros detalles de otras respuestas que ayudan. No estoy convencido de que -> no es un operador sin embargo. ¿Alguien más puede confirmar esto? – AnthonyWJones

+2

Se podría decir que es un operador de nivel de tipo. Más bien, un constructor de tipo de datos. (a -> b) es isomorfo a (a, b). La flecha en el primero es el mismo tipo de cosa que la coma en este último. – Apocalisp

+0

Apocalisp, tomó un par de lecturas (supones que sabía que lo que significaba algo isomorfo me detuvo) pero lo entiendo ahora. – AnthonyWJones

12

Básicamente significa "mapas para". Léelo de esa manera o como "se transforma en" o algo así.

Por lo tanto, desde el F# in 20 minutes 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 (divertido i -> i% 2 = 0) define una función anónima, llamada una 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 incluso.

+0

También se puede utilizar esta referencia: http://research.microsoft.com/fsharp/manual/lexyacc.aspx –

1

De Microsoft:

tipos de función son los tipos dados a valores de la función de primera clase y son escrita int -> int. Son similares a los tipos de delegados .NET, excepto que no reciben nombres. Todos los identificadores de la función F # se pueden utilizar como valores de función de primera clase , y se pueden crear valores de función anónimos utilizando el formulario de expresión (diversión ... -> ...).

4

(a -> b) significa "función de aa 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 utiliza como un contstructor 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.

0

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 al curry funciones:

adder n x y = n + x + y 

En otras palabras: "dame tres cosas, y voy a sumarlos". Cuando le arrojas números, el compilador inferirá los tipos de n x y y.Supongamos que escribe

adder 1 2 3 

El tipo de 1, 2 y 3 es Int. Por lo tanto:

adder :: Int -> Int -> Int -> Int 

Eso es, dame tres enteros, y se convertirá en un entero, con el tiempo, o el mismo que decir:

five :: Int 
five = 5 

Pero, aquí está la parte buena! Prueba esto:

add5 = adder 5 

Como recordarán, el sumador toma un int, int, 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 ha "despegado" de los números enteros (más a la izquierda), y pegado directamente a la función. Mirando más de cerca a la firma de la función, nos damos cuenta de que el -> son asociativo por la derecha, es decir:

addder :: Int -> (Int -> (Int -> Int)) 

Esto debería dejar claro: cuando se da el sumador el primer número entero, que va a evaluar a cualquier cosa que esté a la derecho de la primera flecha, o:

add5andtwomore :: Int -> (Int -> Int) 
add5andtwomore = adder 5 

Ahora puede utilizar add5andtwomore en lugar de "víbora 5". De esta manera, se puede aplicar otro número entero para obtener (por ejemplo) "add5and7andonemore":

add5and7andonemore :: Int -> Int 
add5and7andonemore = adder 5 7 

Como se ve, add5and7andonemore quiere exactamente otro argumento, y cuando se le da uno, llegará a ser pronto un entero!

> add5and7andonemore 9 
=> ((add5andtwomore) 7) 9 
=> ((adder 5) 7) 9) 
<=> adder 5 7 9 

Sustituyendo los parámetros a sumadora (nxy) para (5 7 9), obtenemos:

> adder 5 7 9 = 5 + 7 + 9 
=> 5 + 7 + 9 
=> 21 

De hecho, además también está a una función que toma un entero y le da volver a otro int, por lo que lo anterior es realmente más como:

> 5 + 7 + 9 
=> (+ 5 (+ 7 9)) 
=> (+ 5 16) 
=> 21 

¡Ya lo tiene!

1

Ya hay muchas respuestas excelentes, solo quiero agregar a la conversación otra forma de pensar al respecto.

'->' significa la 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 está 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.

Así que si usted escribe: dejar que fxyz =()

El tipo será f: 'a ->' b -> 'c - unidad>, por lo que si se aplicaba sólo el primer parámetro, el resultado sería una función con curry 'b ->' c -> 'unidad.

1

En el contexto de la definición de una función, es similar a => 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 -> en F # también se utiliza en la coincidencia de patrones, donde significa: si la expresión coincide con la parte entre | y ->, a continuación, lo que viene después -> se debe dar de nuevo como resultado:

let isOne x = match x with 
| 1 -> true 
| _ -> false 
9

Primera pregunta: ¿está 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 pueden encontrar en el contexto de comparación de patrones

match x with 
| 1 -> dosomething 
| _ -> dosomethingelse 

no estoy seguro si esto es también una expresión lambda, o algo más, pero supongo que el 'va a' aún mantiene.

Tal vez lo que realmente están refiriendo es la respuesta de los crípticos 'el F # del analizador:

> let add a b = a + b 
val add: int -> int -> int 

Esto significa (como la mayoría de los ejemplos explican) que añaden un 'val' que toma dos enteros y retornos 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 reparto añadir sólo un int, regrese un (int -> int):

> let inc = add 1 
val inc: int -> int 

Este (currificación) es una de las cosas que hace tan atractivo F #, para mí.

Para información útil sobre F #, he encontrado que los blogs son mucho más útil que cualquiera de la 'documentación' oficial: Aquí están algunos nombres hasta la salida

1

Muchas respuestas excelentes a esta pregunta, gracias a la gente. Me gustaría poner aquí una respuesta editable que reúna las cosas.

Para quienes estén familiarizados con la comprensión de C# -> ser igual que => la expresión de lamba es un buen primer paso. Este uso es: -

fun x y -> x + y + 1 

puede entenderse como el equivalente a: -

(x, y) => x + y + 1; 

Sin embargo es claro que -> tiene un significado más fundemental que se deriva de concepto de que una función que toma dos parámetros tal como lo 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 se describe en lo anterior como esto: -

Int -> Int -> Int 

Realmente me ayudó a saber que -> es correcto asociativo, por tanto, de lo anterior se puede considerar: -

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 del tipo de definición 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 nuevas 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.

+0

Volveré cuando tenga suficiente reputación :) – Benjol

+0

Por lo tanto, en una definición de tipo - Int -> Int -> Int = un func que toma un int y devuelve un func que toma un int y devuelve un int - es ¿ese derecho? –