Práce s řetězci v Logu

9. 10. 2007
Doba čtení: 11 minut

Sdílet

V dnešním článku o jazyce Logo si nejprve řekneme, jak v Logu pracovat s textovými řetězci a poté si popíšeme i některé standardní vstupně/výstupní funkce a procedury dostupné v prakticky všech moderních interpreterech Loga. Jedná se o funkce pro tisk na standardní výstup, čtení ze standardního vstupu apod.

Obsah

1. Práce s řetězci v Logu
2. Zpracování jednotlivých slov a jejich skládání do vět
3. Rozklad slov a vět na složky
4. Operace se znaky
5. Výstupní operace
6. Ovlivnění tisku vnořených seznamů
7. Vstupní operace
8. Odkazy na další informační zdroje
9. Obsah následující části tohoto seriálu

1. Práce s řetězci a funkce dostupné v pokročilejších interpreterech Loga

Programovací jazyk Logo byl původně navržen s ohledem na to, aby se v něm snadno prováděly symbolické výpočty (symbolic computing), podobně jako v programovacím jazyku LISP, který byl ideovým předchůdcem Loga. Není vůbec náhoda, že první testovací implementace Loga byla vytvořena na MIT (Massachusetts Institute of Technology) a BBN (Bolt, Beranek and Newman Inc.), protože právě MIT se velkým dílem podílí na výzkumu umělé inteligence (AI – Artifical Intelligence), při kterém se symbolické výpočty velmi často používají. Logo dokáže zpracovávat symboly jako základní datové typy – to jsme si již ukazovali v předchozích částech tohoto seriálu. Se zpracováním symbolů do značné míry souvisí i práce s textovými řetězci, kterou si podrobněji popíšeme v následujících odstavcích.

Většina programovacích jazyků považuje textové řetězce za statická či dynamická pole znaků, což znamená, že v těchto jazycích převažují operace, které řetězce zpracovávají buď jako celek nebo naopak po jednotlivých znacích. Logo je v tomto ohledu značně odlišné, protože se v něm řetězce jako samostatný datový typ vůbec nevyskytují. Místo řetězců zná Logo věty (sentences), které se skládají z jednotlivých slov (words), přičemž celá věta je chápána jako seznam těchto slov. To znamená, že všechny operace, které pracují se seznamy, mohou pracovat i s takto vytvořenými větami. Jednotlivá slova, která jsou v mnohém podobná klasicky pojatým řetězcům, jsou složena ze znaků (characters), ovšem každé slovo je v Logu chápáno opět jako seznam (znaků), proto je i se slovy možné provádět stejné operace, jako s celými seznamy. To znamená, že místo dvouúrovňového pohledu řetězec–znak se v Logu pracuje se třemi úrovněmi věta–slovo–znak.

2. Zpracování jednotlivých slov a jejich skládání do vět

Nejprve si ukažme práci s jednotlivými slovy. Slova se mohou v programech vyskytovat samostatně, mohou být uvedena ve výrazech nebo je možné je zapisovat ve statických konstruktorech seznamů. Pokud jsou slova umístěna ve statických konstruktorech seznamů, tj. mezi dvojicí hranatých závorek [ a ], zapisují se opravdu jako běžná slova, bez jakéhokoli prefixového nebo postfixového znaku, protože zde nemůže dojít k záměně slova (symbolu) za jméno procedury nebo proměnné – tyto prvky programovacího jazyka se mezi hranatými závorkami nesmí vyskytovat (když by bylo zapotřebí vytvořit seznam například z hodnot proměnných, je nutné použít příkaz list nebo sentence). Například:

[Linux FreeBSD Windows]
[a [b c] [d e] f] 

Pokud se slova vyskytují kdekoli mimo statické konstruktory seznamů, tj. ve výrazech nebo parametrech funkcí, musí před nimi být uveden znak (jedná se o "počítačové“ uvozovky s ASCII kódem 34, nikoli dvojici apostrofů nebo typografické uvozovky!), aby bylo možné jednoznačně odlišit slova od procedur či názvů proměnných. Jednou výjimkou jsou číselné hodnoty, před kterými nemusí být uvozovky uvedeny a také dvě zabudované konstanty Loga – TRUE a FALSE (je jedno, jestli jsou zapsány malými či velkými znaky). Existuje i možnost zapsat prázdné slovo (obdoba prázdného řetězce), které je reprezentováno pouhým znakem . Následuje několik jednoduchých příkladů, ze kterých je také patrné, proč se v Logu jeden z příkazů určených pro zřetězení objektů do seznamů nazývá sentence (česky "věta“):

; vytvoříme dvě proměnné "a" a "b"
; každá proměnná bude obsahovat jedno slovo
make "a "hello
make "b "world

; nová proměnná "c" obsahuje seznam dvou slov
make "c list :a :b

; i proměnná "d" obsahuje seznam dvou slov
make "d sentence :a :b

; ukázka rozdílu mezi procedurami print a show
; (bude vysvětleno v dalších kapitolách)
print :c
hello world
show :c
[ hello world ]
print :d
hello world
show :d
[ hello world ] 

3. Rozklad slov a vět na složky

V předchozích kapitolách jsme si řekli, že slova jsou chápána jako seznamy, jejichž složky jsou představovány samostatnými znaky z tabulky ASCII. Pro přístup k jednotlivým složkám seznamů se používají takzvané selektory, které již známe – jedná se o funkce first, butfirst, last, butlast a item. Slova je tedy možné pomocí těchto funkcí rozkládat na podřetězce a/nebo z nich vybírat jednotlivé znaky, což je ukázáno na následujícím příkladu:

; nejprve vytvoříme řetězec (slovo), které se bude dále zpracovávat
make "retezec "hello

; ukázka použití selektorů

; první znak slova
show first :retezec
h

; slovo bez prvního znaku
show butfirst :retezec
ello

; poslední znak slova
show last :retezec
o

; slovo bez posledního znaku
show butlast :retezec
hell

; přístup k libovolnému znaku
show item 1 :retezec
h

show item 2 :retezec
e

; přístup ke znakům pomocí programové smyčky
repeat 5 [
    show item repcount retezec
]
h
e
l
l
o 

4. Operace se znaky

V Logu je umožněno zpracování jednotlivých znaků, ze kterých se slova skládají, i když v případě Loga se jedná o dosti nízkou úroveň, která mnohdy není využita. Například funkce ascii slouží k převodu jednoho znaku na jeho číselný ekvivalent v kódu ASCII, ale jak je vidět i z níže uvedeného příkladu, je možné zjišťovat i kódy znaků ležících mimo ASCII (což ovšem může vést k nepřenositel­nému kódu):

; číselný ASCII kód znaku 'x'
show ascii "x
120

; číselný ASCII kód znaku '@'
show ascii "@
64

; číselný neASCII kód znaku 'ř'
; (není obecně přenositelné!)
show ascii "ř
248

; smyčka, ve které se vytisknou
; ASCII kódy všech znaků v řetězci
; "hello"
repeat 5 [
    make "znak item repcount "hello
    (show :znak "-> ascii :znak)
]
h -> 104
e -> 101
l -> 108
l -> 108
o -> 111 

Opakem funkce ascii je funkce char, která jako svůj vstup akceptuje číselný kód v rozsahu 32–127 (což je rozsah tisknutelných znaků kódové tabulky ASCII) a vrací znak, který odpovídá danému kódu. Ve skutečnosti však většina implementací Loga akceptuje i číselné kódy vyšší než 127, i když jsme stále omezeni na osmibitové kódování (tj. žádný Unikód) a to dokonce i u těch implementací, které jsou naprogramovány v Javě, která interně  Unikódem pracuje.

repeat 10 [
    type char 64+repcount
]
ABCDEFGHIJ 

5. Výstupní operace

Kromě grafického výstupu, který se v Logu provádí pomocí želví grafiky, je v reálných programech často potřebné tisknout i číselné nebo textové hodnoty, seznamy, pole apod. Prakticky všechny dnes používané implementace programovacího jazyka Logo používají pro tisk údajů na standardní výstup, tj. textový terminál, okno grafického uživatelského rozhraní, připojenou tiskárnu atd., tři základní procedury, které mají názvy print, type a show. Procedura print x vytiskne hodnotu konstanty, proměnné či výrazu x. Za vytištěnou hodnotou následuje automatické odřádkování, tj. případný další tisk již bude probíhat na dalším textovém řádku (konkrétní způsob odřádkování je závislý na použitém zařízení i operačním systému). Pokud by bylo zapotřebí současně vytisknout více hodnot, je možné použít volání této procedury s libovolným počtem parametrů, ovšem celá procedura musí být i se svými parametry umístěna do kulatých „lispovských“ závorek:

(print x y z ...) 

Procedura nazvaná type pracuje velmi podobným způsobem jako výše zmíněná procedura print, ovšem s tím rozdílem, že se po vytištění předané hodnoty či více hodnot (opět pomocí rozšířené syntaxe se závorkami) NEprovádí automatické odřádkování, ale textový kurzor zůstane umístěn za posledním vytištěným znakem. Toto chování oceníme především v případech, kdy je nutné na jeden textový řádek umístit více výpisů, které z různých důvodů není možné sjednotit do jednoho volání print. Při tomto způsobu tisku si však musíme dát pozor na to, že některé implementace Loga mohou z důvodu urychlení vstupních a výstupních operací umisťovat tištěný text do mezipaměti (cache) a zobrazovat až celý textový řádek (ten je dokončen až po implicitním nebo explicitním odřádkování). Může se nám tedy stát, že se hodnoty vytištěné procedurou type ihned nezobrazí. Například v UCBLogu je možné si tisk vynutit zadáním příkazu wait 0, nezávisle na tom, zda bylo odřádkování provedeno.

Třetí procedurou určenou pro tisk hodnot, je procedura show. Ta se chová podobně jako příkaz print, ovšem s rozdílným chováním při tisku seznamů. Zatímco procedura show okolo všech seznamů vypisuje i hranatou otevírací a uzavírací závorku, procedura print toto přidávání znaků na začátek a konec tisku nedělá. Při ladění je výhodnější používat proceduru show (jasně vidíme, že se tiskne seznam), ovšem ve výsledných programech, které pomocí standardního výstupu komunikují s uživateli, se častěji setkáme s procedurou print, protože i textový řetězec je v Logu chápaný jako seznam slov a u řetězců by hranaté závorky na začátku i na konci mohly vadit. Poznamenejme, že způsob tisku polí či vnořených seznamů zůstává nezměněn, tj. zde se procedury show a print chovají naprosto stejně. Ukažme si vše na demonstračním příkladu, ve kterém jsou příkazy zadávané tučným písmem, poznámky jsou psané kurzívou a výstup interpreteru Loga normálním písmem:

; =============================================
; nejprve si ukážeme chování procedur
; show a print při tisku seznamů
make "seznam [1 2 3 4 5]
show :seznam
[1 2 3 4 5]
print :seznam
1 2 3 4 5

; =============================================
; nyní vyzkoušíme tisk seznamu, který
; obsahuje jako své položky podseznamy
make "seznam2 [[1 2] [3 4] [5 [6 7]] 8]
show :seznam2
[[1 2] [3 4] [5 [6 7]] 8]
print :seznam2
[1 2] [3 4] [5 [6 7]] 8

; =============================================
; dále vytvoříme pole o pěti prvcích
; a v programové smyčce inicializujeme
; jeho hodnoty
make "pole array 5
repeat 5 [
    setitem repcount :pole repcount
]
show :pole
{1 2 3 4 5}
print :pole
{1 2 3 4 5}

; =============================================
; a jak se vytiskne prázdné pole, přesněji
; řečeno pole s neinicializovanými prvky?
make "prazdne_pole array 5
show :prazdne_pole
{[] [] [] [] []}
print :prazdne_pole
{[] [] [] [] []}

; =============================================
; následuje vytvoření a tisk seznamu vlastností
; (property list)
; nejprve do seznamu vlastností vložíme tři
; rozdílně pojmenované vlastnosti
pprop "konfigurace "computer "PC
pprop "konfigurace "os       "Linux
pprop "konfigurace "memory   256

show plist "konfigurace
[memory 256 os Linux computer PC]
print plist "konfigurace
memory 256 os Linux computer PC 

6. Ovlivnění tisku vnořených seznamů

Maximální úroveň tisku do sebe vnořených seznamů či polí je možné ovlivnit nastavením proměnné nazvané printdepthlimit. Pokud tato proměnná není inicializovaná, jsou vnořené seznamy a pole tištěny do své maximální hloubky (ta je teoreticky neomezená), ale v případě, že je printdepthlimit nastavena na kladné celé číslo, je tisk položek uložených ve větší úrovni zanoření, než odpovídá tomuto číslu, nahrazen trojicí teček . To je výhodné zejména při ladění, kdy mnohdy nepotřebujeme znát například celou strukturu vytvářeného binárního stromu, ale pouze jeho nejvyšší část. Vše si opět můžeme odzkoušet na jednoduchém příkladu:

; vytvoříme seznam se třemi úrovněmi podseznamů
make "seznam [1 [2 3] [4 [5 [6 7] 8]]]

; tisk celého seznamu
print :seznam
1 [2 3] [4 [5 [6 7] 8]]

; omezení tisku na tři úrovně (dvě podúrovně)
make "printdepthlimit 3
print :seznam
1 [2 3] [4 [5 [... ...] 8]]

; omezení tisku na jednu úroveň (žádnou podúroveň)
make "printdepthlimit 1
print :seznam
1 [... ...] [... ...] 

7. Vstupní operace

Kromě výstupních operací je v reálných programech samozřejmě také nutné získat nějaké informace od uživatele, například formou interaktivního vstupu. Dnes si nebudeme ukazovat žádné pokročilejší funkce využívající grafické uživatelské rozhraní (i když i tyto funkce můžeme v moderních interpreterech Loga nalézt), ale „pouze“ procedury pracující se standardním vstupem, který je v Logu prezentován příkazovým řádkem. Mezi základní vstupní operace, které můžeme nalézt ve vyspělejších implementacích Loga, patří:

Funkce/procedura Zkrácený tvar Význam
readlist rl načtená data jsou chápána jako seznam hodnot se stejnou syntaxí, jako v případě inicializace seznamu ve složených závorkách
readword rw načtení řetězce, který je uložen do jednoho slova, i když obsahuje mezery
readchar rc načtení jednoho znaku, který je uložen ve formě slova (nečeká se na Enter/Return)
readchars n rcs načtení n znaků bez čekání na Enter/Return
readrawline × podobné proceduře readword, ale nezpracovává zpětná lomítka ani další speciální znaky
shell příkaz × spustí v shellu zadaný příkaz a výsledek vrátí ve formě vnořeného seznamu

Následují jednoduché příklady použití:

; načtení dat do seznamu, oddělovačem je mezera
show readlist
a b c d
[a b c d]

; načtení dat do jednoho slova (i s mezerami)
show readword
a b c d
a b c d

; načtení jednoho znaku bez čekání na Enter/Return
show readchar
a
a

; načtení trojice znaků bez čekání na Enter/Return
show readchars 3
abc
abc

; načtení výsledků shellovského příkazu ve formě vnořeného seznamu
show shell "ls
[[Ballblazer.ogg] [Blue_noise.ogg] [Brown_noise.ogg] [Desktop] [Examples] [Gray_noise.ogg] [gvt.gnumeric] [logo_16.html] [logo_16.html~] [Pink_noise.ogg] [Purple_noise.ogg] [RTTY.ogg] [svg.html] [Whitenoisesound.ogg]] 

bitcoin_skoleni

8. Odkazy na další informační zdroje

  1. Young People's Logo Association:
    The Logo Library
  2. StarLogo Pages at MIT,
    http://el.www­.media.mit.edu/grou­ps/el/Projects/star­logo/
  3. StarLogo Pages at Northwestern University,
    http://ccl.nor­thwestern.edu/cm/star­logo/
  4. NETLogo Pages,
    http://ccl.nor­thwestern.edu/ne­tlogo/
  5. MSWLogo,
    http://www.sof­tronix.com/lo­go.html
  6. Massachusetts Institute of Technology,
    http://www.mit­.edu/
  7. Logo resources,
    http://el.medi­a.mit.edu/logo-foundation/re­sources/
  8. Wikipedia EN: Logo Programming Language,
    http://en.wiki­pedia.org/wiki/Lo­go_(programmin­g_language)
  9. Wikipedia EN: Artifical Intelligence,
    http://en.wiki­pedia.org/wiki/Ar­tificial_inte­lligence
  10. Wikipedia CZ: Programovací jazyk Logo,
    http://cs.wiki­pedia.org/wiki/Lo­go_(programova­cí_jazyk)
  11. Wikipedia CZ: Umělá inteligence,
    http://cs.wiki­pedia.org/wiki/U­mělá_inteligen­ce
  12. Wallace Feurzeig:
    The Logo Lineage,
    http://www.ata­riarchives.or­g/deli/logo.php

9. Obsah následující části tohoto seriálu

V další části seriálu o programovacím jazyce Logo si popíšeme některé nestandardní funkce a procedury dostupné v pokročilejších interpreterech Loga. Jedná se o funkce umožňující tisk hodnot na nestandardních zařízeních, práci se soubory, textovým terminálem, komunikaci po síti, podporu vícevláknového běhu programu, multitasking apod.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.