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

externa länkar