Zoeken…


Opmerkingen

Hogere orderfuncties zijn functies die functies als parameters en / of retourfuncties als hun retourwaarden nemen.

Basisprincipes van hogere orderfuncties

Bekijk de gedeeltelijke toepassing voordat u doorgaat.

In Haskell wordt een functie die andere functies als argumenten of retourfuncties kan gebruiken, een functie van hogere orde genoemd .

Dit zijn alle functies van een hogere orde :

map       :: (a -> b) -> [a] -> [b]
filter    :: (a -> Bool) -> [a] -> [a]
takeWhile :: (a -> Bool) -> [a] -> [a]
dropWhile :: (a -> Bool) -> [a] -> [a]
iterate   :: (a -> a) -> a -> [a]
zipWith   :: (a -> b -> c) -> [a] -> [b] -> [c]
scanr     :: (a -> b -> b) -> b -> [a] -> [b]
scanl     :: (b -> a -> b) -> b -> [a] -> [b]

Deze zijn met name handig omdat ze ons in staat stellen nieuwe functies te creëren bovenop de functies die we al hebben, door functies als argumenten door te geven aan andere functies. Vandaar de naam, functies van een hogere orde .

Overwegen:

Prelude> :t (map (+3))
(map (+3)) :: Num b => [b] -> [b]

Prelude> :t (map (=='c'))
(map (=='c')) :: [Char] -> [Bool]

Prelude> :t (map zipWith)
(map zipWith) :: [a -> b -> c] -> [[a] -> [b] -> [c]]

Deze mogelijkheid om eenvoudig functies te maken (zoals bijvoorbeeld door gedeeltelijke toepassing zoals hier gebruikt) is een van de functies die functioneel programmeren bijzonder krachtig maakt en ons in staat stelt korte, elegante oplossingen af te leiden die anders tientallen regels in andere talen zouden vergen. De volgende functie geeft ons bijvoorbeeld het aantal uitgelijnde elementen in twee lijsten.

aligned :: [a] ->  [a] -> Int
aligned xs ys = length (filter id (zipWith (==) xs ys))

Lambda-uitdrukkingen

Lambda-uitdrukkingen zijn vergelijkbaar met anonieme functies in andere talen.

Lambda-uitdrukkingen zijn open formules die ook variabelen specificeren die moeten worden gebonden. Evaluatie (het vinden van de waarde van een functieaanroep) wordt vervolgens bereikt door de gebonden variabelen in het hoofdgedeelte van de lambda-expressie te vervangen door de door de gebruiker opgegeven argumenten. Simpel gezegd, met lambda-expressies kunnen we functies uitdrukken via variabele binding en substitutie .

Lambda-uitdrukkingen zien eruit

\x -> let {y = ...x...} in y

Binnen een lambda-expressie worden de variabelen aan de linkerkant van de pijl beschouwd als gebonden aan de rechterkant, dwz het lichaam van de functie.

Overweeg de wiskundige functie

f(x) = x^2

Als een Haskell-definitie is het dat

f    x =  x^2

f = \x -> x^2

wat betekent dat de functie f equivalent is aan de lambda-uitdrukking \x -> x^2 .

Denk aan de parameter van de hogere-orde functie map , dat is een functie van het type a -> b . In het geval het slechts eenmaal wordt gebruikt in een aanroep naar map en nergens anders in het programma, is het handig om het als een lambda-expressie op te geven in plaats van een dergelijke wegwerpfunctie te benoemen. Geschreven als een lambda-uitdrukking,

\x -> let {y = ...x...} in y

x heeft een waarde van type a , ...x... is een Haskell-expressie die verwijst naar de variabele x , en y heeft een waarde van type b . Dus we zouden bijvoorbeeld het volgende kunnen schrijven

map (\x -> x + 3)

map (\(x,y) -> x * y)

map (\xs -> 'c':xs) ["apples", "oranges", "mangos"]

map (\f -> zipWith f [1..5] [1..5]) [(+), (*), (-)]

Currying

In Haskell worden alle functies als vervuild beschouwd: dat wil zeggen dat alle functies in Haskell maar één argument hebben.

Laten we de functie div :

div :: Int -> Int -> Int

Als we deze functie met 6 en 2 noemen, krijgen we niet verrassend 3:

Prelude> div 6 2
3

Dit gedraagt zich echter niet helemaal zoals we denken. Eerste div 6 wordt geëvalueerd en retourneert een functie van het type Int -> Int . Deze resulterende functie wordt vervolgens toegepast op de waarde 2 die 3 oplevert.

Als we naar de typeaanduiding van een functie kijken, kunnen we ons denken verleggen van "neemt twee argumenten van het type Int " naar "neemt één Int en geeft een functie terug die een Int ". Dit wordt opnieuw bevestigd als we bedenken dat pijlen in de typeaantekening aan het recht zijn gekoppeld, dus div kan in feite als volgt worden gelezen:

div :: Int -> (Int -> Int)

Over het algemeen kunnen de meeste programmeurs dit gedrag ten minste negeren terwijl ze de taal leren. Vanuit theoretisch oogpunt zijn "formele bewijzen eenvoudiger wanneer alle functies uniform worden behandeld (één argument in, één resultaat)."



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow