Elm Language
Funkcje i częściowe zastosowanie
Szukaj…
Składnia
- - zdefiniowanie funkcji bez argumentów wygląda tak samo jak zwykłe zdefiniowanie wartości
language = "Elm" - - wywołanie funkcji bez argumentów poprzez podanie jej nazwy
język - - parametry są oddzielone spacjami i są zgodne z nazwą funkcji
dodaj xy = x + y - - wywołać funkcję w ten sam sposób
dodaj 5 2 - - częściowo zastosować funkcję, podając tylko niektóre jej parametry
przyrost = dodaj 1 - - użyj operatora |>, aby przekazać wyrażenie po lewej stronie do funkcji po prawej stronie
dziesięć = 9 |> przyrost - - <| operator przekazuje wyrażenie po prawej stronie do funkcji po lewej stronie
przyrost <| dodaj 5 4 - - połącz / skomponuj dwie funkcje razem z operatorem >>
backwardsYell = String.reverse >> String.toUpper - - << działa tak samo w odwrotnym kierunku
backwardsYell = String.toUpper << String.reverse - - funkcja o niealfanumerycznej nazwie w nawiasie tworzy nowego operatora
(#) xy = x * y
dziesięć = 5 # 2 - - dowolny operator infix staje się normalną funkcją po zawinięciu go w nawiasy
dziesięć = (+) 5 5 - - opcjonalne adnotacje typu pojawiają się nad deklaracjami funkcji
isTen: Int -> Bool
isTen n = jeśli n == 10 to Prawda, inaczej Fałsz
Przegląd
Składnia aplikacji funkcji w Elm nie używa nawiasów ani przecinków i jest wrażliwa na spacje.
Aby zdefiniować funkcję, podaj jej nazwę multiplyByTwo i argumenty x , wszelkie operacje po znaku równości = są zwracane z funkcji.
multiplyByTwo x =
x * 2
Aby wywołać funkcję, podaj jej nazwę i argumenty:
multiplyByTwo 2 -- 4
Zauważ, że składnia taka jak multiplyByTwo(2) nie jest konieczna (nawet jeśli kompilator nie narzeka). Nawiasy służą jedynie do ustalenia pierwszeństwa:
> 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
Wyrażenia lambda
Wiąz ma specjalną składnię dla wyrażeń lambda lub funkcji anonimowych:
\arguments -> returnedValue
Na przykład, jak widać w List.filter :
> List.filter (\num -> num > 1) [1,2,3]
[2,3] : List number
Bardziej do głębi, ukośnik, \ , służy do oznaczenia początku wyrażenia lambda, a strzałka, -> , służy do oddzielenia argumentów od treści funkcji. Jeśli argumentów jest więcej, są one oddzielane spacją:
normalFunction x y = x + y
-- is equivalent to
lambdaFunction = \x y -> x + y
> normalFunction 1 2
3 : number
> lambdaFunction 1 2
3 : number
Zmienne lokalne
Możliwe jest zdefiniowanie lokalnych zmiennych wewnątrz funkcji do
- zmniejszyć liczbę powtórzeń kodu
- nadaj nazwę podwyrażeniom
- zmniejszyć liczbę przekazywanych argumentów.
Konstrukcja do tego jest 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!
Kolejność definicji w pierwszej części let nie ma znaczenia!
outOfOrder =
let
x =
y + 1 -- the compiler can handle this
y =
100
in
x + y
> outOfOrder
201 : number
Częściowe zastosowanie
Częściowa aplikacja oznacza wywołanie funkcji z mniejszą liczbą argumentów i zapisanie wyniku jako innej funkcji (która czeka na resztę argumentów).
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
Jako akademicki sidotum, Elm może to zrobić z powodu curry za kulisami.
Ścisła i opóźniona ocena
W wiązie wartość funkcji jest obliczana po zastosowaniu ostatniego argumentu. W poniższym przykładzie diagnostyka z log zostanie wydrukowana, gdy f zostanie wywołany z 3 argumentami lub zastosowana zostanie curry forma f z ostatnim argumentem.
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
Czasami chcesz uniemożliwić zastosowanie funkcji od razu. Typowym zastosowaniem w Lazy.lazy jest Lazy.lazy który zapewnia abstrakcję do kontrolowania, kiedy funkcje są stosowane.
lazy : (() -> a) -> Lazy a
Leniwe obliczenia przyjmują funkcję jednego () lub argumentu typu Unit . Typ jednostki to typowo argument zastępczy. Na liście argumentów odpowiedni argument jest określony jako _ , co oznacza, że wartość nie jest używana. Wartość jednostki w wiązie jest określona specjalnym symbolem () który może koncepcyjnie przedstawiać pustą krotkę lub dziurę. Przypomina pustą listę argumentów w C, JavaScript i innych językach, które używają nawiasów do wywołań funkcji, ale jest to zwykła wartość.
W naszym przykładzie f można zabezpieczyć przed natychmiastową oceną za pomocą 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
Ocena funkcji jest opóźniona za każdym razem, gdy funkcja jest częściowo zastosowana.
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
Wiąz ma always funkcję, której nie można użyć do opóźnienia oceny. Ponieważ wiąz ocenia wszystkie argumenty funkcji niezależnie od tego, czy i kiedy zostanie użyty wynik zastosowania aplikacji funkcji, zawijanie aplikacji funkcji always nie spowoduje opóźnienia, ponieważ f jest w pełni stosowane jako parametr do always .
alwaysF = always (f "a" "b" "c") -- <function> : a -> String
-- Diagnostic: ["a","b","c"] -- Evaluation wasn't delayed.
Operatory i notacja infix
Wiąz pozwala na zdefiniowanie niestandardowych operatorów infix.
Operatory Infix są definiowane za pomocą nawiasów wokół nazwy funkcji.
Rozważ ten przykład operatora infix dla konstrukcji Tuples 1 => True -- (1, True) :
(=>) : a -> b -> ( a, b )
(=>) a b =
( a, b )
Większość funkcji w Elm jest zdefiniowana w notacji przedrostkowej.
Zastosuj dowolną funkcję za pomocą notacji niecałkowitej, podając pierwszy argument przed nazwą funkcji ujętą w poważny znak akcentujący:
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]