Pregunta

He estado intentando entrar y salir de F# por un tiempo, pero sigo desanimándome.¿Por qué?

Porque no importa qué recurso para 'principiantes' intente mirar, veo ejemplos muy simples que comienzan a usar el operador ->.

Sin embargo, hasta el momento no he encontrado ningún lugar que proporcione una explicación clara y sencilla de lo que significa este operador.Es como si debiera ser tan obvio que no necesitara explicación ni siquiera para los novatos.

Por lo tanto, debo ser muy tonto o tal vez sean casi 3 décadas de experiencia previa lo que me frena.

¿Alguien puede explicarlo o señalar un recurso verdaderamente accesible que lo explique?

¿Fue útil?

Solución

'->' no es un operador.Aparece en la sintaxis de F# en varios lugares y su significado depende de cómo se utiliza como parte de una construcción más amplia.

Dentro de un tipo, '->' describe 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 "coincidente", '->' es una 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

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 deberse a la suposición errónea de que '->' es "un operador" con un único significado.Una analogía podría ser "." En C#, si nunca ha visto ningún código antes, e intente analizar el "". Operador Basado en ver "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 quedan claras.

Otros consejos

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

Entonces, desde el F# en 20 minutos 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 (diversión i -> i % 2 = 0) define una función anónima, llamada expresión de 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 es o no incluso.

Primera pregunta: ¿está familiarizado con las expresiones lambda en C#?Si es así, el -> en F# es el mismo que el => en C# (creo que lo leíste '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 de si esto también es una expresión lambda o algo más, pero supongo que "va a" todavía se mantiene.

Quizás a lo que realmente te refieres son a las respuestas "crípticas" del analizador de F#:

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

Esto significa (como explican la mayoría de los ejemplos) que add es un 'val' que toma dos enteros y devuelve un entero.Para mí, esto era totalmente opaco al principio.Quiero decir, ¿cómo sé que add no es un val que toma un int y devuelve dos int?

Bueno, la cuestión es que, en cierto sentido, sí.Si le doy add solo un int, obtengo un (int -> int):

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

Esto (curry) es una de las cosas que hace que F# sea tan sexy para mí.

Para obtener información útil sobre F#, descubrí que los blogs son MUCHO más útiles que cualquiera de la 'documentación' oficial:Aquí hay algunos nombres para revisar

(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 número entero y devuelve una cadena.También se utiliza como constructor de tales valores, como en

val f : (int -> int) = fun n -> n * 2

lo que crea un valor que es una función de algún número n a ese mismo número multiplicado por dos.

Ya hay muchas respuestas excelentes aquí, 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).Como int/string devuelve float/char.

Donde se vuelve interesante es en el caso en 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:sea ​​f x y z = ()

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

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 se les dan nombres.Todos los identificadores de la función F# se pueden usar como valores de función de primera clase, y los valores de función anónimo se pueden crear utilizando (Fun ...-> ...) forma de expresión.

Muchas respuestas excelentes a estas preguntas, gracias gente.Me gustaría poner aquí una respuesta editable que combine las cosas.

Para aquellos familiarizados con la comprensión de C# -> ser lo mismo que => expresión 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, está claro que -> tiene un significado más fundamental que surge del concepto de que una función que toma dos parámetros como los anteriores 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 así: -

Int -> Int -> Int

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

Int -> (Int -> Int)

¡Ajá!Tenemos una función que toma Int y devuelve (Int -> Int) (¿una función curry?).

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 cualquier función que toma un Int y devuelve un Int.

¿También es útil que -> aparezca en otra sintaxis, como coincidencia, pero no tiene el mismo significado?¿Es eso correcto?No estoy seguro de que lo sea.Sospecho que tiene el mismo significado pero todavía no tengo el vocabulario para expresarlo.

Tenga en cuenta que el propósito de esta respuesta no es generar más respuestas, sino que ustedes la editen en colaboración para crear una respuesta más definitiva.En última instancia, sería bueno que se eliminaran todas las incertidumbres y tonterías (como las de este párrafo) y se agregaran mejores ejemplos.Intentemos mantener esta respuesta lo más accesible posible para los no iniciados.

En el contexto de definir 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 usa 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

Lo bueno de lenguajes como Haskell (es muy similar en F#, pero no conozco la sintaxis exacta; aunque esto debería ayudarte a entender ->) es que puedes aplicar solo partes del argumento para crear curry funciones:

adder n x y = n + x + y

En otras palabras:"Dame tres cosas y las sumaré".Cuando le arrojas números, el compilador inferirá los tipos de n x e y.di 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 números enteros y me convertiré en un número entero, eventualmente, o lo mismo que decir:

five :: Int
five = 5

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

add5 = adder 5

Como recuerdas, el sumador toma un int, un int, un int y te devuelve un int.Sin embargo, esa no es toda la verdad, como verá en breve.De hecho, add5 tendrá este tipo:

add5 :: Int -> Int -> Int

Será como si hubieras "despegado" los números enteros (el más a la izquierda) y los hubieras pegado directamente a la función.Mirando más de cerca la firma de la función, notamos que -> son asociativos por la derecha, es decir:

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

Esto debería dejarlo bastante claro:cuando le das al sumador el primer número entero, se evaluará como lo que esté a la derecha de la primera flecha, o:

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

Ahora puedes usar add5andtwomore en lugar de "sumador 5".De esta manera, puedes aplicar otro número entero para obtener (digamos) "add5and7andonemore":

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

Como puedes ver, add5and7andonemore quiere exactamente otro argumento, y cuando le das 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 del sumador (n x y) 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

¡Ahí tienes!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top