Elm Language
Functies en gedeeltelijke toepassing
Zoeken…
Syntaxis
- - het definiëren van een functie zonder argumenten lijkt op het eenvoudig definiëren van een waarde
taal = "Elm" - - een functie zonder argumenten aanroepen door de naam te vermelden
taal - - parameters worden gescheiden door spaties en volgen de naam van de functie
voeg xy = x + y toe - - roep een functie op dezelfde manier aan
voeg 5 2 toe - - een functie gedeeltelijk toepassen door slechts enkele van de parameters ervan te verstrekken
ophogen = toevoegen 1 - - gebruik de operator |> om de uitdrukking links door te geven aan de functie rechts
tien = 9 |> ophogen - - de <| operator geeft de uitdrukking aan de rechterkant door aan de functie aan de linkerkant
toename <| voeg 5 4 toe - - keten / stel twee functies samen met de >> operator
backwardsYell = String.reverse >> String.toUpper - - de << werkt hetzelfde in omgekeerde richting
backwardsYell = String.toUpper << String.reverse - - een functie met een niet-alfanumerieke naam tussen haakjes maakt een nieuwe operator aan
(#) xy = x * y
tien = 5 # 2 - - elke infix-operator wordt een normale functie wanneer u deze tussen haakjes plaatst
tien = (+) 5 5 - - optionele type-annotaties verschijnen boven functieverklaringen
isTen: Int -> Bool
isTen n = if n == 10 dan Waar anders Niet waar
Overzicht
De syntaxis van de functie-applicatie in Elm maakt geen gebruik van haakjes of komma's en is in plaats daarvan witruimtegevoelig.
Om een functie te definiëren, geeft u de naam multiplyByTwo en argumenten x , alle bewerkingen na is gelijk aan = is wat wordt geretourneerd door een functie.
multiplyByTwo x =
x * 2
Om een functie aan te roepen, geeft u de naam en argumenten op:
multiplyByTwo 2 -- 4
Merk op dat syntaxis zoals multiplyByTwo(2) niet nodig is (hoewel de compiler niet klaagt). De haakjes dienen alleen om voorrang op te lossen:
> 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
Lambda-uitdrukkingen
Elm heeft een speciale syntaxis voor lambda-expressies of anonieme functies:
\arguments -> returnedValue
Bijvoorbeeld, zoals te zien in List.filter :
> List.filter (\num -> num > 1) [1,2,3]
[2,3] : List number
Meer diepgaand wordt een achterwaartse schuine streep, \ , gebruikt om het begin van lambda-expressie te markeren, en de pijl, -> , wordt gebruikt om argumenten af te bakenen uit de hoofdtekst. Als er meer argumenten zijn, worden deze gescheiden door een spatie:
normalFunction x y = x + y
-- is equivalent to
lambdaFunction = \x y -> x + y
> normalFunction 1 2
3 : number
> lambdaFunction 1 2
3 : number
Lokale variabelen
Het is mogelijk om lokale variabelen in een functie te definiëren
- verminder herhaling van code
- geef naam aan subexpressies
- verminder het aantal doorgegeven argumenten.
De constructie hiervoor is 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!
De volgorde van definities in het eerste deel van let doet er niet toe!
outOfOrder =
let
x =
y + 1 -- the compiler can handle this
y =
100
in
x + y
> outOfOrder
201 : number
Gedeeltelijke toepassing
Gedeeltelijke toepassing betekent het aanroepen van een functie met minder argumenten dan het heeft en het resultaat opslaan als een andere functie (die wacht op de rest van de argumenten).
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
Als academische sidenote kan Elm dit doen door achter de schermen te curren .
Strikte en vertraagde evaluatie
In iep wordt de waarde van een functie berekend wanneer het laatste argument wordt toegepast. In het onderstaande voorbeeld wordt de diagnose uit het log afgedrukt wanneer f wordt aangeroepen met 3 argumenten of wordt een gecurryde vorm van f toegepast met het laatste argument.
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
Soms wil je voorkomen dat een functie meteen wordt toegepast. Een typisch gebruik in iep is Lazy.lazy dat een abstractie biedt voor het regelen wanneer functies worden toegepast.
lazy : (() -> a) -> Lazy a
Luie berekeningen hebben een functie van één () of Unit argument. Het eenheidstype is conventioneel het type van een argument voor tijdelijke aanduiding. In een lijst met argumenten wordt het bijbehorende argument gespecificeerd als _ , wat aangeeft dat de waarde niet wordt gebruikt. De eenheidswaarde in iep wordt aangegeven door het speciale symbool () dat conceptueel een lege tuple of een hole kan vertegenwoordigen. Het lijkt op de lege lijst met argumenten in C, Javascript en andere talen die haakjes gebruiken voor functieaanroepen, maar het is een normale waarde.
In ons voorbeeld kan f worden beschermd tegen onmiddellijk evalueren met een 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
Functie-evaluatie wordt vertraagd wanneer een functie gedeeltelijk wordt toegepast.
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 heeft een always functie, die niet kan worden gebruikt om de evaluatie uit te stellen. Omdat iep alle functieargumenten evalueert, ongeacht of en wanneer het resultaat van de functie-toepassing wordt gebruikt, zal het inpakken van een functie-toepassing always geen vertraging veroorzaken, omdat f always als parameter volledig wordt toegepast.
alwaysF = always (f "a" "b" "c") -- <function> : a -> String
-- Diagnostic: ["a","b","c"] -- Evaluation wasn't delayed.
Infix-operators en infix-notatie
Elm staat de definitie van aangepaste infix-operatoren toe.
Infix-operatoren worden gedefinieerd met behulp van haakjes rond de naam van een functie.
Beschouw dit voorbeeld van infix-operator voor constructie Tuples 1 => True -- (1, True) :
(=>) : a -> b -> ( a, b )
(=>) a b =
( a, b )
De meeste functies in Elm worden gedefinieerd in de prefixnotatie.
Pas elke functie toe met behulp van infixnotatie door het eerste argument op te geven vóór de functienaam omsloten door een ernstig accentteken:
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]