Haskell Language
Delvis tillämpning
Sök…
Anmärkningar
Låt oss rensa upp några missuppfattningar som nybörjare kan göra.
Du kan ha stött på funktioner som:
max :: (Ord a) => a -> a -> a
max m n
| m >= n = m
| otherwise = n
Nybörjare visar vanligtvis max :: (Ord a) => a -> a -> a
som funktion som tar två argument (värden) av typ a
och returnerar ett värde av typ a
. Men vad som verkligen händer är att max
tar ett argument av typ a
och returnerar en funktion av typ a -> a
. Denna funktion tar sedan ett argument av typ a
och returnerar ett slutligt värde av typ a
.
Faktum är att max
kan skrivas som max :: (Ord a) => a -> (a -> a)
Tänk på typsignaturen för max
:
Prelude> :t max
max :: Ord a => a -> a -> a
Prelude> :t (max 75)
(max 75) :: (Num a, Ord a) => a -> a
Prelude> :t (max "Fury Road")
(max "Fury Road") :: [Char] -> [Char]
Prelude> :t (max "Fury Road" "Furiosa")
(max "Fury Road" "Furiosa") :: [Char]
max 75
och max "Fury Road"
kanske inte ser ut som funktioner, men i själva verket är de det.
Förvirringen härrör från det faktum att i matematik och många, andra, vanliga programmeringsspråk, får vi ha funktioner som tar flera argument. Men i Haskell kan funktioner bara ta ett argument och de kan returnera antingen värden som a
eller funktioner som a -> a
.
Delvis tillämpad tilläggsfunktion
Vi kan använda en partiell applikation för att "låsa" det första argumentet. Efter att ha använt ett argument sitter vi kvar med en funktion som förväntar oss ytterligare ett argument innan resultatet returneras.
(+) :: Int -> Int -> Int
addOne :: Int -> Int
addOne = (+) 1
Vi kan sedan använda addOne
för att lägga till en till en Int
.
> addOne 5
6
> map addOne [1,2,3]
[2,3,4]
Återgå till en delvis tillämpad funktion
Återvända delvis tillämpade funktioner är en teknik för att skriva kort kod.
add :: Int -> Int -> Int
add x = (+x)
add 5 2
I detta exempel (+ x) är en delvis tillämpad funktion. Observera att den andra parametern till tilläggsfunktionen inte behöver specificeras i funktionsdefinitionen.
Resultatet av att ringa add 5 2
är sju.
sektioner
Sektionering är ett kortfattat sätt att delvis tillämpa argument på infixoperatörer.
Om vi till exempel vill skriva en funktion som lägger till "ing" i slutet av ett ord kan vi använda ett avsnitt för att definiera en funktion kortfattat.
> (++ "ing") "laugh"
"laughing"
Lägg märke till hur vi delvis har använt det andra argumentet. Normalt kan vi bara delvis tillämpa argumenten i den angivna ordningen.
Vi kan också använda vänster sektionering för att delvis tillämpa det första argumentet.
> ("re" ++) "do"
"redo"
Vi kan på motsvarande sätt skriva detta med hjälp av normal prefix partiell applikation:
> ((++) "re") "do"
"redo"
En anmärkning om subtraktion
Nybörjare ofta felaktigt avsnitt negation.
> map (-1) [1,2,3]
***error: Could not deduce...
Detta fungerar inte eftersom -1
är tolkat som bokstavligt -1
snarare än den sektionsoperatör -
tillämpas på 1
. subtract
finns för att kringgå detta problem.
> map (subtract 1) [1,2,3]
[0,1,2]