Mnohé z programovacích jazykov sú dnes už málo používané. Aj pojem toho čo taký počítač vlastne robí je dosť odlišný. V minulosti došli do výpočtového strediska formuláre na spracovanie mzdy alebo sčítania obyvateľov či zdravotné výkazy. Potom kopa ľudí naťukalo údaje na strojoch ktoré ich vyradili do diernych štítkov či pások a šlo sa počítať. A počítač zrátaval, prerátaval, sumarizoval, zoraďoval a na výstupe čosi nadieroval na iné sady štítkov či nahral na magnetickú pásku alebo vytlačil na tlačiarni a poslal späť zadávateľovi ako v prípade tých výplat.
Prípadne počítač rátal nejakú vedeckú simuláciu či prevádzal iné náročné výpočty , napríklad aj dnes počítače rátajú predpoveď počasia podľa matematického modelu. A to je iné programovanie ako je potrebné na firemné web stránky alebo formuláre na online nákupy. Počítače boli pomalé, mali malú pamäť a čas ich používania bol drahý. Preto sa hľadal taký spôsob programovania , ktorý by čo najlepšie zvládol daný problém pri čo najmenšej potrebe času a prostriedkov na jeho zápis a vykonávanie.
Dnes už sú počítače omnoho výkonnejšie a mnohé z požiadaviek na programovanie už nie sú prvoradé. Veď aj obyčajný smartfón má 4GB pamäte čo bola pred 20 rokmi kapacita bežného pevného disku osobného počítača.
LISP je zástupcom tzv. funkcionálneho programovania čo je jeden z mnohých prístupov k tomu ako sa problém programom rieši. Zápis programu je vlastne funkcia ktorá sa vyhodnocuje. Tj nie je to primárne postupnosť príkazov čo presne sa má robiť ale výraz ktorým program prechádza a jeho vyhodnotením získava výsledok.
LISP používa tzv. prefixovú notáciu. Tj. na rozdiel od jazyka FORTH sú operátory pred výrazom. Tj namiesto 2+3 sa zapisuje + 2 3 . Je to po FORTRANE druhý najstarší stále používaný jazyk ktorý vznikol v roku 1958.
Výrazy v zatvorkach su ihneď vyhodnotené.
* (+ 2 3)
5
podobne zložitejšii vyraz sa zapisuje takto . tj. (2+4)*(2+2) :
(*(+ 2 3) (+ 2 2))
20
Podobne existuju funkcie na výber časti reťazca :
* (subseq "abcdefghijklmnopqrst" 2)
"cdefghijklmnopqrst"
* (subseq "abcdefghijklmnopqrst" 2 6 )
"cdef"
*
Nastavenie konštanty:
* (defconstant sadzba-zdravotne 4)
SADZBA-ZDRAVOTNE
*
Premennej priradíme hodnotu napr takto:
* (setq y 20)
20
* (setq z 10)
10
* (+ y z)
30
*
Teraz skúsime príklad s vypočtom čistej mzdy.
Skúsime rovno vytvoriť výraz ktorý vyráta hodnotu čistej mzdy. Na začiatok si premennú hruba-mzda zadefinujeme pred vypočtom.
(defconstant hruba-mzda 1000)
Súčet poistných odvodov by bol :
( + (/ ( 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100))
134.0
*
Daň by sme vypočítali nejako takto :
(/ ( (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100)
93.29
*
Takže čistá mzda je hruba-mzda - odvody - daň a to by hádam mohlo byt takto a po istom chaose v zátvorkách to konečne vracia správnu hodnotu.
Fakticky okrem toho krkolomného zápisu v prefixovej notácii, sa rovnaká funkcia dč zapísať v ľubovolnom jazyku.
(- hruba-mzda ( + (/ ( 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) (/ (* (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100))
772.71
*
Teraz by bolo potrebné doplniť vypisovanie textu. Na to slúži funkcia read:
* (+ 2 (read))
3
5
*
Zadali sme z klávesnice 3 a zobrazil sa nám výsledok výrazu , tj. 5.
Premennú možno zadefinovať hodnotou zadanou z klávesnice nejako takto:
* (setq nacitaj-z-klavesnice (read))
56
56
* nacitaj-z-klavesnice
56
*
Pre vypocet cistej mzdy sme zadefinovali funkciu. Ta ma parameter hruba-mzda a vracia hodnotu cistej mzdy.
(defun cista (hruba-mzda) (- hruba-mzda ( + (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) (/ (* (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100)))
CISTA
* (cista 400)
351.83398
* (cista 100)
141.396
* (cista 1000)
772.71
*
Ostáva to dať celé nejako dokopy a veru dať to do jednej funkcie sa mi nejako nedarí, buď to skúšam zle alebo sa to v rámci povolených konštrukcií robí nejako inak.
Skúsme funkciu na výpis. Tá s jedným textovým argumentom funguje.
* (defun zadajmzdu () (print "Zadaj vysku hrubej mzdy: "))
ZADAJMZDU
*
Aj funkcia načítania čísla do premennej funguje. Musí tam byt defun (vstupne premenne) ( vyraz ) .
Teda ak vypisuje alebo len načítava tak je miesto premennej prázdne ().
* (defun citaj-mzdu () (setq x (read)))
CITAJ-MZDU
A oba funguju :
* (zadajmzdu)
"Zadaj vysku hrubej mzdy: "
"Zadaj vysku hrubej mzdy: "
* (citaj-mzdu)
1234
1234
Teraz skúsime vytvoriť funkciu ktorá bude volať ďalšie funkcie.
No, je to zatiaľ najnezvyklejšií jazyk. Editor poskytuje aký-taký prehľad kde je chyba . V nasledujúcom som najprv zabudol dať v názve druhej funkcie pomlčku, a tak ju to vyhodnotilo ako novu nedefinovanú. Po oprave to prešlo.
* (defun nacitaj-mzdu-x () (zadajmzdu) (citajmzdu ))
; in: DEFUN NACITAJ-MZDU-X
; (CITAJMZDU)
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::CITAJMZDU
;
; compilation unit finished
; Undefined function:
; CITAJMZDU
; caught 1 STYLE-WARNING condition
NACITAJ-MZDU-X
* (defun nacitaj-mzdu-x () (zadajmzdu) (citaj-mzdu))
WARNING: redefining COMMON-LISP-USER::NACITAJ-MZDU-X in DEFUN / tu pise ze raz s chybou to uz zadefinovalo ale preslo to.
NACITAJ-MZDU-X
*
A teraz zavoláme novu funkciu ktorá vypíše text , očakáva vstup čisla a priradí ho premennnej x :
Zas to robi čosi iné ako by človek čakal. Naprv čaká na vstup a potom vypíše text .
NACITAJ-MZDU-X
* (nacitaj-mzdu-x)
123
"Zadaj vysku hrubej mzdy: "
123
*
Skúsme na to ist inak. Nebudeme volat funkciu na nacitanie, ale rovno nacitame.
* (defun nacitaj () (print "zadaj mzdu:") (setq x (read)))
NACITAJ
Nepomohlo.
* (nacitaj)
34
Jazyk LISP umožňuje vytvárať makrá tak som to skúsil, evidentne ak mi nejdú jednoduchšie veci, tak tie ak nie aj nové chyby urobím aj v tomto.
* (defmacro vypocet ()
(print "Zadaj vysku hrubej mzdy: ")
(setq x (read))
(print "Cista mzda je: ")
(x))
; in: DEFMACRO VYPOCET
; (X)
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::X
;
; compilation unit finished
; Undefined function:
; X
; caught 1 STYLE-WARNING condition
WARNING: redefining COMMON-LISP-USER::VYPOCET in DEFMACRO
VYPOCET
*
Ani za ten svet.
* (defmacro vypocet ()
(print "Zadaj vysku hrubej mzdy: ")
(defvar x 1000)
(setq x (read))
(print "Cista mzda je: ")
x)
WARNING: redefining COMMON-LISP-USER::VYPOCET in DEFMACRO
VYPOCET
* (vypocet)
45
"Zadaj vysku hrubej mzdy: "
"Cista mzda je: "
45
*
Zas a znova to najprv čaká na vstup a až potom vypíše úvodný text.
Pravdepodobne ignorujem nejaký zásadný proces ktorým prebieha vyhodnotenie výrazu. Pri niekoľkých výpisoch textu sa tieto podarí zoradiť. Vyzerá to tak, že najprv sa vyhodnotia vnorené funkcie ku ktorým patrí aj to READ a preto to žiada vstup ešte pred výpismi.
Isto by sa to dalo nejakým spôsobom ošetriť, len neviem narýchlo akým.
* (defun printtext () (print "abc") (print "def") (print "xyz"))
WARNING: redefining COMMON-LISP-USER::PRINTTEXT in DEFUN
PRINTTEXT
* (printtext)
"abc"
"def"
"xyz"
"xyz"
* (defun nacitaj-a-zobraz () (print "Zadaj hrubu mzdu:") (setq x (read)))
WARNING: redefining COMMON-LISP-USER::NACITAJ-A-ZOBRAZ in DEFUN
NACITAJ-A-ZOBRAZ
* (nacitaj-a-zobraz)
789
"Zadaj hrubu mzdu:"
789
*
Bude to teda v dôsledku poradia vyhodnocovania.
Tak ostáva použiť spôsob kde sa jednotlivé výrazy postupne nahrávajú a vyhodnocujú. Len aj to má svoje pravidlá.
Program by hádam vyzeral nasledovne.
(print "Zadaj hrubu mzdu:")
(setq hruba-mzda (read))
(defun cista (hruba-mzda) (- hruba-mzda ( + (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) (/ (* (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100)))
(defun dan (hruba-mzda) (/ (* (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100))
(print "Nemocenske ")
(/ (* 1.4 hruba-mzda)100)
(print "Starobne")
(/ (* 4 hruba-mzda) 100)
(print "Invalidne")
( /(* 3 hruba-mzda)100)
(print "Poistenie nezamestnanosti")
( /(* 1 hruba-mzda)100)
(print "Zdravotne poistenie")
( /(* 4 hruba-mzda) 100)
(print "Dan je")
(dan (hruba-mzda))
(print "Cista mzda je:")
(cista (hruba-mzda))
Nuž ale ani spustiť , ani preloziť...
* (compile-file "cistamzda.lsp")
; compiling file "C://cistamzda.lsp" (written 27 APR 2022 01:34:22 PM):
; file: C://cistamzda.lsp
; in: CISTA (HRUBA-MZDA)
; (CISTA (HRUBA-MZDA))
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::HRUBA-MZDA
; in: DAN (HRUBA-MZDA)
; (DAN (HRUBA-MZDA))
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::HRUBA-MZDA
; in: / (* 3 HRUBA-MZDA)
; (/ (* 3 HRUBA-MZDA) 100)
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::HRUBA-MZDA
; in: / (* 4 HRUBA-MZDA)
; (/ (* 4 HRUBA-MZDA) 100)
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::HRUBA-MZDA
; in: / (* 1.4 HRUBA-MZDA)
; (/ (* 1.4 HRUBA-MZDA) 100)
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::HRUBA-MZDA
;
; caught WARNING:
; 2 more uses of undefined variable HRUBA-MZDA
;
; compilation unit finished
; Undefined function:
; HRUBA-MZDA
; Undefined variable:
; HRUBA-MZDA
; caught 4 WARNING conditions
; caught 2 STYLE-WARNING conditions
; wrote C://cistamzda.fasl
; compilation finished in 0:00:00.054
#P"C://cistamzda.fasl"
T
T
====
Problém je s definíciou premennej a s vyhodnotením niektorých výrazov to považuje moju premennú za funkciu bez definicíe.
Takže na 5-ty krát sme sa dúspešnému prekladu bez chýb.
* (compile-file "cistamzda05.lsp")
; compiling file "C://cistamzda05.lsp" (written 27 APR 2022 03:03:30 PM):
; wrote C://cistamzda05.fasl
; compilation finished in 0:00:00.012
#P"C://cistamzda05.fasl"
NIL
NIL
*
Akurát to nejde spustiť alebo to funguje ináč ako som si myslel.
Skúsime to obísť a napísať jednu funkciu ktorej zavolaním s argumentom výšky hubej mzdy nám vráti presne to, čo chceme.
Celú funkciu si nazveme program a skúsime odstrániť všetky chyby ktoré sa tam objavili a veru v tej rýchlosti ich zopár bolo.
* (defun program (x) (setf hruba-mzda x)
(defun cista (hruba-mzda) (- hruba-mzda ( + (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) (/ (* (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100)))
(defun dan (hruba-mzda) (/ (* (- hruba-mzda 375 (/ (* 1.4 hruba-mzda)100) (/ (* 4 hruba-mzda) 100) ( /(* 3 hruba-mzda)100) ( /(* 1 hruba-mzda)100) ( /(* 4 hruba-mzda) 100)) 19) 100))
(print "Nemocenske ")
(print (/ (* 1.4 hruba-mzda)100))
(print "Starobne")
(print (/ (* 4 hruba-mzda) 100))
(print "Invalidne")
(print ( /(* 3 hruba-mzda)100))
(print "Poistenie nezamestnanosti")
(print ( /(* 1 hruba-mzda)100))
(print "Zdravotne poistenie")
(print ( /(* 4 hruba-mzda) 100))
(print "Dan je")
(print (dan hruba-mzda))
(print "Cista mzda je:")
(print (cista hruba-mzda)))
WARNING: redefining COMMON-LISP-USER::PROGRAM in DEFUN
PROGRAM
* (program 1000) / tu necháme interpreter vyhodnotiť výraz v ktorom je naša funkcia s argumentom výšky hrubej mzdy
WARNING: redefining COMMON-LISP-USER::CISTA in DEFUN / to nám len oznamuje že vnorená definícia funkcie sa vykonala
WARNING: redefining COMMON-LISP-USER::DAN in DEFUN
// tuto už vidno konečne očakávaný výstup
"Nemocenske "
14.0
"Starobne"
40
"Invalidne"
30
"Poistenie nezamestnanosti"
10
"Zdravotne poistenie"
40
"Dan je"
93.29
"Cista mzda je:"
772.71
772.71
* (program 2000) / volanie s inou hodnotou
WARNING: redefining COMMON-LISP-USER::CISTA in DEFUN
WARNING: redefining COMMON-LISP-USER::DAN in DEFUN
"Nemocenske "
28.0
"Starobne"
80
"Invalidne"
60
"Poistenie nezamestnanosti"
20
"Zdravotne poistenie"
80
"Dan je"
257.83
"Cista mzda je:"
1474.17
1474.17
*
Hurááá , konečne to funguje ako má. Kládlo to nezvyčajný odpor. Hádam aj preto, že ak je LISP v podstate matematický formalizmus na zápis výrazov, zrejme bolo treba naozaj najprv pochopiť ako presne sa tie výrazy vyhodnocujú. Nuž v MIT kde LISP vznikol majú na to zrejme lepšie mozgy. Takýto jednoduchý numerický príklad samozrejme neukazuje to, čo je na LISPe také dôležité a aké problémy sa týmto prístupom dajú riešiť.
LISP je v úplne inej skupine programovacích jazykov ako drvivá väčšina ostatných. V novších prevedeniach majú podobné vlastnosti jazyky Haskell, Scheme a Clojure.
PS: No a takto a podobne to treba skúšať každý deň zopár hodín v priebehu 5 či 10 rokov. A potom sa z vás (ak na to máte) stane raz programátor ovládajúci ten svoj výrez z obrovského množstva rôznych oblastí čomu sa môžete ako programátor venovať...