Tyst programmering
Tyst programmering , även kallad punktfri stil , är ett programmeringsparadigm där funktionsdefinitioner inte identifierar de argument (eller "punkter") som de verkar på. Istället utgör definitionerna bara andra funktioner, bland annat kombinatorer som manipulerar argumenten. Tyst programmering är av teoretiskt intresse, eftersom den strikta användningen av komposition resulterar i program som är väl anpassade för ekvationsresonemang . Det är också den naturliga stilen för vissa programmeringsspråk , inklusive APL och dess derivator, och sammanlänkade språk som Forth . Bristen på argumentnamngivning ger punktfri stil ett rykte om att vara onödigt obskyr, därav epitetet "pointless style".
Unix -skript använder paradigmet med pipes .
Nyckelidén i tyst programmering är att hjälpa till att arbeta på lämplig abstraktionsnivå.
Exempel
Pytonorm
Tyst programmering kan illustreras med följande Python- kod. En sekvens av operationer som följande:
def exempel ( x ): return baz ( bar ( foo ( x )))
... är skriven i punktfri stil som sammansättningen av en sekvens av funktioner, utan parametrar:
från functools importera partiell , reducera def compose ( * fns ): returnera partiell ( reducera , lambda v , fn : fn ( v ), fns ) exempel = compose ( foo , bar , baz )
För ett mer komplext exempel, Haskell-koden p = ((.) f) . g
kan översättas som:
p = partiell ( komponera , partiell ( komponera , f ), g )
Funktionell programmering
Ett enkelt exempel (i Haskell ) är ett program som beräknar summan av en lista med tal. Vi kan definiera summafunktionen rekursivt med en spetsig stil (jfr värde -nivåprogrammering ) som:
summa ( x : xs ) = x + summa xs summa [] = 0
Men genom att använda en vikning kan vi ersätta detta med:
0 summa xs = foldr ( + ) xs
Och då behövs inte argumentet, så det här förenklar till
summa = mapp ( + ) 0
vilket är poängfritt.
Ett annat exempel använder funktionssammansättning :
p x y z = f ( g x y ) z
Följande Haskell-liknande pseudokod visar hur man reducerar en funktionsdefinition till dess punktfria motsvarighet:
p = \ x -> \ y -> \ z -> f ( g x y ) z = \ x -> \ y -> f ( g x y ) = \ x -> \ y -> ( f . ( g ) x )) y = \ x -> f . ( g x ) ( * Här används infix - komponeringsoperatorn " . " som en curryfunktion . * ) = \ x -> (( . ) f ) ( g x ) = \ x - > ((( . ) f ) . g ) x p = ( ( . ) f ) . g
Slutligen, för att se ett komplext exempel, föreställ dig ett kartfilterprogram som tar en lista, tillämpar en funktion på den och sedan filtrerar elementen baserat på ett kriterium
mf criteria operator list = filterkriterier ( map operator list ) _
Det kan uttryckas punktfritt som
mf = ( . karta ) . ( . ) . filtrera
Notera att, som nämnts tidigare, punkterna i 'punktfri' hänvisar till argumenten, inte till användningen av prickar; en vanlig missuppfattning.
Ett fåtal program har skrivits för att automatiskt konvertera ett Haskell-uttryck till en punktfri form.
APL familj
I J förekommer samma sorts punktfri kod i en funktion som är gjord för att beräkna medelvärdet av en lista (array) med tal:
medel =: +/ % #
+/
summerar objekten i arrayen genom att mappa ( /
) summering ( +
) till arrayen. %
dividerar summan med antalet element ( #
) i arrayen.
Eulers formel uttryckt tyst:
cos =: 2 o . ] sin =: 1 o . ] Euler =: ^@ j . = cos j . synd
( j.
är en primitiv funktion vars monadiska definition är 0j1
gånger x och vars dyadiska definition är x+0j1×y
.) Samma tysta beräkningar som uttrycks i Dyalog APL :
avg ← + ⌿ ÷ ≢ cos ← 2 ○ ⊢ sin ← 1 ○ ⊢ EulerCalc ← cos + 0j1 × sin ⍝ 0j1 är vad som vanligtvis skrivs som i EulerDirect ← * 0J ❍ ❍ ❋ 1 Gör de 2 metoderna producera samma resultat? EulerCheck ← EulerDirect = EulerCalc EulerCheck ¯1 1 2 3 1 1 1 1 ⍝ Ja, hittills har det gått bra!
Stackbaserad
I stack-orienterade programmeringsspråk (och konkatenativa sådana , varav de flesta är stackbaserade [ citat behövs ] ), används punktfria metoder vanligtvis. Till exempel kan en procedur för att beräkna Fibonacci-talen se ut så här i PostScript :
0
/fib { dup dup 1 eq exch eq or not { dup 1 sub fib exch 2 sub fib add } if } def
Rörledningar
Unix pipeline
I Unix-skript är funktionerna datorprogram som tar emot data från standardinmatning och skickar resultaten till standardutdata . Till exempel,
sortera | uniq -c | sortera -rn
är en tyst eller poängfri komposition som returnerar antalet av sina argument och argumenten, i ordningen av minskande antal. 'sort' och 'uniq' är funktionerna, '-c' och '-rn' styr funktionerna, men argumenten nämns inte. Röret '|' är sammansättningsoperatör.
På grund av hur pipelines fungerar är det normalt bara möjligt att skicka ett "argument" åt gången i form av ett par standard input/output-strömmar. Även om extra filbeskrivningar kan öppnas från namngivna pipes , utgör detta inte längre en punktfri stil.
jq
jq är ett JSON-orienterat programmeringsspråk där '|' symbolen används för att ansluta filter för att bilda en pipeline på ett välbekant sätt. Till exempel:
[1,2] | Lägg till
utvärderas till 3. (Ja, JSON-matrisen är ett jq-filter som utvärderas till en matris.)
Även om de liknar Unix-pipelines tillåter jq-pipelines att inkommande data skickas till mer än en mottagare på RHS för '|' som parallellt. Till exempel kommer programmet "add/length" att beräkna medelvärdet av siffrorna i en array, så att:
[1,2] | lägg till/längd
uppskattas till 1,5
Liknande:
[1,2] | [längd, lägg till, lägg till/längd]
utvärderas till [2,3,1.5]
En punkt ('.') kan användas för att definiera en fästpunkt på RHS, t.ex.
1 | [., .]
utvärderar till [1,1]
och liknande:
2 | pow(.; .)
utvärderas till 4 eftersom pow(x;y) är x till potensen y.
Fibonnaci-sekvens
Ett tyst jq-program för att generera Fibonnaci-sekvensen skulle vara:
[0,1] | recurse( [sista, lägg till] ) | först
Här är [0,1] det initiala paret som ska tas som de två första objekten i Fibonnaci-sekvensen. (Paret [1,1] kan också användas för variantdefinitionen.)
De alfabetiska tokens är inbyggda filter: "första" och "sista" sänder ut de första och sista elementen i deras inmatningsmatriser; och "rekurs(f)" applicerar ett filter, f, på dess ingång rekursivt.
jq tillåter också att nya filter definieras i en tyst stil, t.ex.
def fib: [0,1] | recurse( [sista, lägg till] ) | först;
Sammansättning av unära funktioner
I avsnittet om Python i den här artikeln beaktas följande Python-definition:
def exempel ( x ): returnera baz ( bar ( foo ( x )))
I punktfri stil kan detta skrivas i Python som:
exempel = komponera ( foo , bar , baz )
I jq skulle den motsvarande punktfria definitionen vara:
def exempel: foo | bar | baz;
Se även
- Kombinationslogik
- Konkatenativt programmeringsspråk
- Programmering på funktionsnivå
- Joy (programmeringsspråk) , modernt mycket tyst språk
externa länkar
- Rena funktioner i APL och J Hur man använder tyst programmering i alla APL-liknande språk
- Stängda applikativa språk 1971 - 1976 ff , i John W. Backus (Publications)