Konkatenativt programmeringsspråk

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 2 januari 2016; kontroller kräver 11 redigeringar .

Ett konkatenativt programmeringsspråk  är ett programmeringsspråk baserat på det faktum att sammanlänkningen av två stycken kod uttrycker deras sammansättning . I ett sådant språk används den implicita specifikationen av funktionsargument flitigt (se meningslös programmering ), nya funktioner definieras som sammansättning av funktioner och sammanlänkning används istället för tillämpning [1] . Detta tillvägagångssätt står i motsats till applikativ programmering .

Många konkatenativa språk använder postfix-notation och en stack för att lagra argument och returnera värden för operationer, så sammanfogade språk betyder vanligtvis stack-språk. Konkatenativa språk kan dock byggas på andra principer, så termerna stack language och konkatenativa språk är inte synonyma.

Konkatenativa språk är enkla, effektiva och lätta att implementera, så de mest populära språken av denna typ används i programmerbara räknare och för inbäddning i små mikroprocessorsystem. Till exempel används det sammanlänkade språket RPL i Hewlett-Packard HP-28 och HP-48 programmerbara räknare . Programmeringsspråket Forth har implementerats på många processorer med mycket begränsade beräkningsmöjligheter [2] , till exempel användes det på Jupiter ACE -datorn med ett basminne på endast 1 KB. Men på grund av deras ovanlighet och svårigheter att läsa källkoden för program, har konkatenativa programmeringsspråk förblivit nischade.

Det vanligaste konkatenativa språket är PostScript -sidbeskrivningsspråket , av vilket en begränsad delmängd används i PDF . Dess tolk är inbyggd i många högpresterande skrivare.

Definition

Ett programmeringsspråk kallas konkatenativt om det uppfyller följande krav:

I ett konkatenativt språk är varje uttryck en funktion. Det finns ingen speciell applikationsoperation, för att tillämpa funktionen på argumenten räcker det att sätta funktionsnamnet bredvid argumenten, det vill säga att utföra text "limning" (sammansättning). Nya funktioner definieras också av konkatenering, som helt enkelt är en sekvens av andra funktionsnamn.

Låt funktioner fooav två argument och barett argument ges. För att tillämpa foopå argument, i prefixnotation , räcker det att komponera ett uttryck så här:

foo 4 5

Applicera nu funktionen barpå resultatet av funktionen foo:

bar foo 4 5

Låt oss slutligen definiera en funktion bazsom en sammanlänkning av tre funktioner:

define baz
    bar foo 4
end-define

Uttrycket baz 8är ekvivalent med uttrycket bar foo 4 8. Det vill säga namnet på vilken funktion som helst kan ersättas med texten i dess definition och det korrekta uttrycket kan erhållas. Denna enkla princip definierar särdragen för sammanlänkade språk, deras fördelar och nackdelar.

Funktioner

För att sammanlänkningen av kodfragment alltid ska uttrycka sin sammansättning måste språket ha funktioner av endast ett argument. [3] I det här fallet kan du vägra att explicit specificera argumentet, så med hjälp av ett enhetligt prefix eller postfix-notation kan du skapa ett programmeringsspråk där sammanlänkningen av kodfragment uttrycker deras sammansättning, det vill säga ett sammanlänkande språk.

Ett enkelt och effektivt sätt att implementera detta tillvägagångssätt är att använda en stack . Funktioner tar argument från stacken och skjuter resultatet till stacken. Därför kan vi säga att i konkatenativa stackprogrammeringsspråk tar funktioner ett argument - stackens tillstånd, och returnerar ett nytt tillstånd för stacken. [4] Dessa språk använder vanligtvis postfix-notation eftersom stacken fungerar i LIFO .

Det finns andra sätt. Till exempel tar en funktion programmets text och returnerar den med några ändringar som återspeglar dess arbete. Ett mycket enkelt och flexibelt homoikoniskt språk kan byggas på denna princip. [5] Det är möjligt att bygga ett språk kring principen för UNIX-pipeline : varje funktion tar en sträng och returnerar en ny sträng efter bearbetning. [6] Till skillnad från den tidigare principen innehåller texten som skickas till funktionen bara argument, inte hela programmet. Dessa metoder kan fungera med både prefix och postfix notation.

Istället för en stack kan andra datastrukturer användas, såsom en eller en deque (deque) [7] .

Idén med ett sammanlänkningsspråk är detta: alla uttryck är funktioner som tar en del av samma datastruktur och returnerar dess nya tillstånd. Denna datastruktur (stack, deque, kö, textsträng, etc.) spelar rollen som lim för att "limma" funktioner i ett program, den lagrar programmets tillstånd. Detta tillvägagångssätt definierar fördelarna och nackdelarna med sammanlänkade språk.

Fördelar:

Brister:

Implementeringar

Det första konkatenativa språket på hög nivå var Forth , utvecklat av Charles Moore i slutet av 1960-talet och början av 1970-talet. Den använde en typlös stack och var lätt att implementera och mycket effektiv, vilket gjorde det möjligt att implementera kompilatorer även med extremt begränsade datorresurser. Forth påverkade avsevärt efterföljande konkatenativa språk.

Föreläsare och programmerare Manfred von Thun vid La Trobe University , influerad av John Backus berömda föreläsning "Kan programmering befrias från von Neumanns stil?" utvecklade programmeringsspråket Joy stack och lade de teoretiska grunderna för konkatenativ programmering. Det var Joy-språket som först kallades sammanfogande.

Influerad av Forth och Joy skapade Slava Pestov programmeringsspråket Factor stack 2003 . Det är placerat som ett "praktiskt stackprogrammeringsspråk". Senare utvecklades de stackkonkatenativa språken Cat och Kitten , som kännetecknas av statisk typning . Ett annat modernt sammanfogningsspråk, min , har en minimalistisk syntax och en mycket kompakt implementering (cirka 1 megabyte) och används i HastySite- webbplatsgeneratorn .

Av de specialiserade stackspråken är de mest kända PostScript , som används för att beskriva sidor och skriva ut dem, samt RPL , programmeringsspråket för HP-28 och HP-48 miniräknare .

Arbeta med stacken

De flesta konkatenativa programmeringsspråk använder stacken för att skicka argument. Detta beror på den enkla implementeringen och stackens egenskaper, vilket är bekvämt att använda med postfix-notation. Överväg att arbeta med stacken med hjälp av språket Forth som exempel.

I Forth består ett program av ord separerade med mellanslag. Om ordet är en siffra, skjuts det upp på toppen av stapeln. Om ord är namnet på en funktion, så kallas den funktionen (i fjärde terminologi kallas funktioner för ord). Den tar argument från stacken och skjuter resultatet till stacken. Tänk på det enklaste programmet, som består av fyra ord:

3 4 + .

De två första orden är siffror, så de skjuts upp på högen. Då kallas funktionen +, som tar två nummer från stacken, lägger till dem och skjuter resultatet till stacken. Då kallas funktionen ., som visar numret från stacken. Således föregår argumenten funktionen, varför denna notation kallas postfix.

Svårigheter och övervinna dem

Konkatenativa språk för allmänna ändamål har inte vunnit någon betydande popularitet. Detta beror på deras specifika fördelar och nackdelar, som är en konsekvens av grundprincipen: alla funktioner tar ett argument och returnerar ett värde. När exakt detta krävs finns det inga problem, och sammanlänkade språk låter dig skriva mycket enkla, koncisa och tydliga program. Anta att ett sammanlänkningsspråk med postfix-notation har följande funktioner som accepterar och returnerar textsträngar:

input - returnerar texten som användaren skrivit in print - visar text på skärmen upcase - Ändrar gemener till versaler i en sträng first_word - returnerar det första ordet i en sträng (klipper strängen till första blanksteg efter det första ordet)

Låt oss använda dem för att skriva ett program som visar användarens namn med versaler:

input first_word upcase print

Svårigheter uppstår när du behöver använda funktioner med olika antal argument. I ett stack-språk måste du placera argumenten i en viss ordning, och ofta måste du byta runt dem. Om ett argument används flera gånger i en funktion måste det också dupliceras. Detta leder till svårbegripliga uttryck. Till exempel funktionen

f x y z = y² + x² − |y|

i stackspråket skrivs så här:

f = drop dup dup × swap abs rot3 dup × swap − +

Använda variabler

Variabler används uttryckligen i moderna konkatenativa språk som Kitten och min för att övervinna dessa svårigheter. På kattungespråk deklareras variabler så här:

->x; // variabel x får sitt värde från stacken 5 -> y; // y = 5 1 2 3 -> xyz; // x = 1; y=2; z = 3

Tänk på funktionen av att kvadrera ett tal. Traditionellt för stack-språk i Kitten skrivs det så här: [8]

define square (Int32 -> Int32):
    dup (*)

Och så kan det skrivas om med en variabel:

define square (Int32 -> Int32):
    -> x;
    x * x

I detta enklaste exempel är detta ingen speciell mening. Men om ett argument eller argument används många gånger i en funktion, förenklar användningen av variabler avsevärt att skriva programmet och läsa källkoden. Ett fragment av programkoden som visar låten 99 flaskor öl :

definiera ölflaskor (Int32 -> +IO): ->x; xvers om (x > 1): (x - 1) ölflaskor

I programmeringsspråket min används symboler på liknande sätt:

x define  ; символ x получит значение из стека
:x        ; сокращённая запись
8 :x      ; x = 8

Tänk till exempel på ett min- program som returnerar sant om en fil är större än 1 megabyte och nyligen har modifierats:

dup dup
"\.zip$" match
swap fsize 1000000 > and
swap mtime now 3600 - >

Med hjälp av symbolen kan du undvika duplicering och omarrangering av stackelement och avsevärt förbättra kodens läsbarhet:

:filepath
filepath "\.zip$" match
filepath fsize 1000000 >
filepath mtime now 3600 - >
and and

Användningen av variabler för sammanlänkade språk närmare applikativa, men det finns fortfarande grundläggande skillnader mellan dem. I konkatenativa språk kan programmeraren välja att använda stacken (eller en liknande mekanism) eller deklarera variabler. Dessutom är mekanismen för att arbeta med variabler ganska transparent och hanterbar. Detta ger flexibilitet och möjlighet till en effektiv och relativt enkel implementering.

Se även

Anteckningar

  1. John Purdy. Varför konkatenativ programmering  är viktig . Hämtad 23 januari 2018. Arkiverad från originalet 24 januari 2018.
  2. Oleg Paramonov. Aliens: The Strange Architecture of Alien Computers . Hämtad 25 januari 2018. Arkiverad från originalet 26 januari 2018.
  3. Xah Lee. Vad är poängfri programmering? (punktfri funktionssyntax  ) . Hämtad 25 januari 2018. Arkiverad från originalet 26 januari 2018.
  4. potomushto. Staplade programmeringsspråk . Hämtad 25 januari 2018. Arkiverad från originalet 26 januari 2018.
  5. Sparist. Om:  Huvudsida . Hämtad 25 januari 2018. Arkiverad från originalet 10 september 2017.
  6. Xah Lee. Unix Pipe som funktionellt  språk . Hämtad 25 januari 2018. Arkiverad från originalet 26 januari 2018.
  7. Deque  . _ Hämtad 25 januari 2018. Arkiverad från originalet 26 januari 2018.
  8. John Purdy. Varför konkatenativ programmering  är viktig . Hämtad 25 januari 2018. Arkiverad från originalet 25 januari 2018.

Länkar