Elm Language
Funciones y aplicación parcial.
Buscar..
Sintaxis
- - Definir una función sin argumentos parece lo mismo que simplemente definir un valor
language = "Elm" - - llamar a una función sin argumentos indicando su nombre
idioma - - Los parámetros están separados por espacios y siguen el nombre de la función.
agrega xy = x + y - - llamar a una función de la misma manera
añadir 5 2 - - aplicar parcialmente una función proporcionando solo algunos de sus parámetros
incremento = agregar 1 - - use el operador |> para pasar la expresión de la izquierda a la función de la derecha
ten = 9 |> incremento - - el <| el operador pasa la expresión de la derecha a la función de la izquierda
incremento <| añadir 5 4 - - encadenar / componer dos funciones junto con el >> operador
backwardsYell = String.reverse >> String.toUpper - - El << funciona igual en sentido inverso.
backwardsYell = String.toUpper << String.reverse - - una función con un nombre no alfanumérico entre paréntesis crea un nuevo operador
(#) xy = x * y
diez = 5 # 2 - - cualquier operador de infijo se convierte en una función normal cuando lo envuelve entre paréntesis
diez = (+) 5 5 - - Las anotaciones de tipo opcionales aparecen arriba de las declaraciones de funciones.
isTen: Int -> Bool
isTen n = if n == 10 entonces True más False
Visión general
La sintaxis de la aplicación de la función en Elm no usa paréntesis ni comas, y en su lugar es sensible al espacio en blanco.
Para definir una función, especifique su nombre multiplyByTwo y argumentos x , cualquier operación después del signo igual = es lo que se devuelve de una función.
multiplyByTwo x =
x * 2
Para llamar a una función, especifique su nombre y argumentos:
multiplyByTwo 2 -- 4
Tenga en cuenta que la sintaxis como multiplyByTwo(2) no es necesaria (aunque el compilador no se queja). Los paréntesis solo sirven para resolver la precedencia:
> multiplyByTwo multiplyByTwo 2
-- error, thinks it's getting two arguments, but it only needs one
> multiplyByTwo (multiplyByTwo 2)
4 : number
> multiplyByTwo 2 + 2
6 : number
-- same as (multiplyByTwo 2) + 2
> multiplyByTwo (2 + 2)
8 : number
Expresiones lambda
Elm tiene una sintaxis especial para expresiones lambda o funciones anónimas:
\arguments -> returnedValue
Por ejemplo, como se ve en List.filter :
> List.filter (\num -> num > 1) [1,2,3]
[2,3] : List number
Más a la profundidad, se usa una barra invertida, \ , para marcar el comienzo de la expresión lambda, y la flecha, -> , se usa para delimitar argumentos del cuerpo de la función. Si hay más argumentos, se separan por un espacio:
normalFunction x y = x + y
-- is equivalent to
lambdaFunction = \x y -> x + y
> normalFunction 1 2
3 : number
> lambdaFunction 1 2
3 : number
Variables locales
Es posible definir variables locales dentro de una función para
- reducir la repetición de código
- dar nombre a subexpresiones
- Reducir la cantidad de argumentos pasados.
El constructo para esto se let ... in ...
bigNumbers =
let
allNumbers =
[1..100]
isBig number =
number > 95
in
List.filter isBig allNumbers
> bigNumbers
[96,97,98,99,100] : List number
> allNumbers
-- error, doesn't know what allNumbers is!
El orden de las definiciones en la primera parte de let no importa!
outOfOrder =
let
x =
y + 1 -- the compiler can handle this
y =
100
in
x + y
> outOfOrder
201 : number
Solicitud parcial
La aplicación parcial significa llamar a una función con menos argumentos de los que tiene y guardar el resultado como otra función (que espera el resto de los argumentos).
multiplyBy: Int -> Int -> Int
multiplyBy x y =
x * y
multiplyByTwo : Int -> Int -- one Int has disappeared! we now know what x is.
multiplyByTwo =
multiplyBy 2
> multiplyByTwo 2
4 : Int
> multiplyByTwo 4
8 : Int
Como una nota de orientación académica, Elm puede hacer esto debido al curry detrás de escena.
Evaluación estricta y demorada.
En elm, el valor de una función se calcula cuando se aplica el último argumento. En el siguiente ejemplo, el diagnóstico desde el log se imprimirá cuando f se invoque con 3 argumentos o se aplique una forma currada de f con el último argumento.
import String
import Debug exposing (log)
f a b c = String.join "," (log "Diagnostic" [a,b,c]) -- <function> : String -> String -> String -> String
f2 = f "a1" "b2" -- <function> : String -> String
f "A" "B" "C"
-- Diagnostic: ["A","B","C"]
"A,B,C" : String
f2 "c3"
-- Diagnostic: ["a1","b2","c3"]
"a1,b2,c3" : String
A veces querrá evitar que una función se aplique de inmediato. Un uso típico en elm es Lazy.lazy que proporciona una abstracción para controlar cuándo se aplican las funciones.
lazy : (() -> a) -> Lazy a
Los cálculos perezosos toman una función de uno () o argumento de tipo de Unit . El tipo de unidad es convencionalmente el tipo de un argumento de marcador de posición. En una lista de argumentos, el argumento correspondiente se especifica como _ , lo que indica que el valor no se usa. El valor de la unidad en olmo se especifica mediante el símbolo especial () que puede representar conceptualmente una tupla vacía o un agujero. Se parece a la lista de argumentos vacía en C, Javascript y otros idiomas que usan paréntesis para llamadas a funciones, pero es un valor ordinario.
En nuestro ejemplo, f puede ser protegido para que no se evalúe inmediatamente con un lambda:
doit f = f () -- <function> : (() -> a) -> a
whatToDo = \_ -> f "a" "b" "c" -- <function> : a -> String
-- f is not evaluated yet
doit whatToDo
-- Diagnostic: ["a","b","c"]
"a,b,c" : String
La evaluación de la función se retrasa cada vez que una función se aplica parcialmente.
defer a f = \_ -> f a -- <function> : a -> (a -> b) -> c -> b
delayF = f "a" "b" |> defer "c" -- <function> : a -> String
doit delayF
-- Diagnostic: ["a","b","c"]
"a,b,c" : String
Elm tiene una función de always , que no puede usarse para retrasar la evaluación. Debido a que elm evalúa todos los argumentos de la función independientemente de si se usa el resultado de la aplicación de función y cuándo, el ajuste de una aplicación de función no always causará un retraso, porque f se aplica completamente como parámetro para always .
alwaysF = always (f "a" "b" "c") -- <function> : a -> String
-- Diagnostic: ["a","b","c"] -- Evaluation wasn't delayed.
Operadores de infijo y notación de infijo.
Elm permite la definición de operadores de infijo personalizados.
Los operadores de infijo se definen utilizando paréntesis alrededor del nombre de una función.
Considere este ejemplo de operador infijo para construcciones Tuples 1 => True -- (1, True) :
(=>) : a -> b -> ( a, b )
(=>) a b =
( a, b )
La mayoría de las funciones en Elm se definen en la notación de prefijo.
Aplique cualquier función utilizando la notación de infijo especificando el primer argumento antes del nombre de la función incluido con el carácter de acento grave:
import List exposing (append)
append [1,1,2] [3,5,8] -- [1,1,2,3,5,8]
[1,1,2] `append` [3,5,8] -- [1,1,2,3,5,8]