Język multi-paradygmatowy Oz – przykłady Mozart/Oz
Przyszło mi się zmierzyć z nowym paradygmatem programowania, mianowicie programowaniem funkcyjnym. Od kilku lat zajmuje się programowaniem. Na początku pisałem imperatywnie, później obiektowo, ale nigdy nie funkcyjnie. Przyznam, że musiałem zmienić odrobinę spojrzenie na kod i samo programowanie. Jednak po krótkiej, ale jakże ciekawej batalii stoczonej na płaszczyźnie mojej klawiatury muszę powiedzieć, że udało się. Jednak spokojna głowa ten paradygmat nie trafi do mojego TOP 3.
Na zajęciach piszemy w języku OCaml i Oz (o pierwszym z nich napiszę później). Teraz skupmy się na języku Oz. Jest to język multi-paradygmatowy, czyli wspomaga kilka paradygmatów. W tym przypadku są jest to:
1. Programowanie w logice
2. Programowanie funkcyjne
3. Programowanie imperatywne
4. Programowanie obiektowe
5. Programowanie deklaratywne
Początki Oz’a sięgają 1991 roku jak to często bywa stworzył go student. Od 1996 roku pieczę nad projektem ma konsorcjum Mozart (często możemy zauważyć w sieci pisownię Oz/Mozart). Projekt jest udostępniany na licencji open source. Składnia języka na początku wydała mi się dość przyjemna, ale z czasem dała ostro popalić. Z języka korzystałem tylko do celów edukacyjnych dlatego nie jestem wstanie powiedzieć wam nic nowego czego nie przeczytacie w dokumentacji i tutorialu (ahhh to co tygryski lubią najbardziej)
Jako, że w internecie jest bardzo mało przykładów związanych z językiem Oz postanowiłem to zmienić. Oto kilka prostych programów.
Funkcja Rev (reverse – przyjmuje jako argument listę) odwracająca listę (rekursja ogonowa).
1 2 3 4 5 6 7 8 9 10 | declare fun {Rev L} local fun {Pom L Acc} case L of nil then Acc [] H|T then {Pom T H|Acc} end end in {Pom L nil} end end |
Funkcja Length która zwraca długość listy przyjętej jako argument.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | declare fun {Length Lst} local fun {Length_acm Lst Acm} if Lst==nil then Acm else {Length_acm Lst.2 Acm+1} end end in {Length_acm Lst 0} end end %przykładowa tablica declare L = 1|2|3|4|5|nil %wydrukowanie wyniku {Show {Length L}} |
Dalej przedstawię zadania z list ćwiczeń, które to rozwiązywałem na zajęciach, niestety nie wszystkie zadania są optymalne obliczeniowo, wiele z nich można usprawnić:
1. Zdefiniuj funkcję Flatten1, która dla argumentu będącego listą list tworzy listę złożoną z elementów wszystkich podlist z zachowaniem ich kolejności, np. {Flatten1 [[5 6] [1 2 3]]} zwraca [5 6 1 2 3], czyli spłaszcza listę o jeden poziom.
1 2 3 4 5 6 7 8 9 10 11 | declare fun {Flatten1 L} if L==nil then nil else {Append L.1{Flatten1 L.2}} end end declare Lst = [[5 6 1 2 3] nil [3 4 3] [3]] {Show {Flatten1 Lst}} |
2. Zdefiniuj funkcję Count obliczającą ile razy dany obiekt występuje w danej liście, np. {Count ‘a’ ['a' 'l' 'a']} zwraca 2.
1 2 3 4 5 6 7 8 9 10 | declare fun {Count Z Lst} if Lst==nil then 0 else if Z==Lst.1 then 1+{Count Z Lst.2} else 0+{Count Z Lst.2} end end end {Show {Count 'a' a|b|a|b|a|b|nil}} |
3. Zdefiniuj funkcję Duplicate powtarzającą dany obiekt określoną liczbę razy i zwracającą wynik w postaci listy, np. {Duplicate ‘la‘ 3} →['la' 'la' 'la'].
1 2 3 4 5 6 7 | declare fun {Duplicate O N} if N==0 then nil else O|{Duplicate O N-1} end end {Show {Duplicate 'a' 6}} |
4. Zdefiniuj funkcję Sqr_list podnoszącą do kwadratu wszystkie elementy danej listy liczb, np. {Sqr_list [1 2 ~3]} → [1 4 9].
1 2 3 4 5 6 7 8 9 10 | declare fun {Sqr_list Lst} if Lst==nil then nil else Lst.1*Lst.1|{Sqr_list Lst.2} end end declare L = 3|4|nil {Show {Sqr_list L}} |
5. Zdefiniuj funkcję Palindrome sprawdzającą, czy dana lista jest palindromem, tj. równa się sobie samej przy odwróconej kolejności elementów, np. {Palindrome ['a' 'l' 'a']} zwraca true.
1 2 3 4 5 6 7 8 9 10 | declare fun {Palindrome Lst} if Lst==nil then nil else Lst=={Reverse Lst} end end declare L = k|a|j|a|k|nil {Show {Palindrome L}} |
6. Zdefiniuj funkcję ListLength obliczjącą długość dowolnej listy.
1 2 3 4 5 6 7 8 9 10 | declare fun {ListLength Lst} if Lst==nil then 0 else 1+{ListLength Lst.2} end end declare L = 1|2|3|4|nil {Show {ListLength L}} |
7. Liczby Fibonacciego są zdefiniowane następująco:
f(0) = 0
f(1) = 1
f(n+2) = f(n) + f(n+1)
Napisz dwie funkcje, które dla danego n znajdują n-tą liczbę Fibonacciego: pierwszą opartą bezpośrednio na powyższej definicji i drugą, wykorzystującą rekursję ogonową. Porównaj ich szybkość wykonania, obliczając np. 37-mą liczbę Fibonacciego.
1 2 3 4 5 6 7 8 9 | declare fun {Fib N} if N==0 then 0 else if N==1 then 1 else {Fib N-1}+{Fib N-2} end end end {Show {Fib 37}} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | declare fun { Fib_tail N} local fun {Fib N1 N2 I} if I=<2 then N2 else local Next = N1+N2 in {Fib N2 Next I-1} end end end in {Fib 1 1 N} end end {Show {Fib_tail 37}} |
8. Zdefiniuj funkcję Initsegment : ‘a list * ‘a list -> bool sprawdzającą w czasie liniowym, czy pierwsza lista stanowi początkowy segment drugiej listy. Każda lista jest swoim początkowym segmentem, lista pusta jest początkowym segmentem każdej listy.
1 2 3 4 5 6 7 8 9 10 11 | declare fun {Initsegment L1 L2} case L1 of nil then true [] H|T then if H==L2.1 then {Initsegment T L2.2} else false end end end {Show {Initsegment 2|3|nil 1|2|3|4|nil}} |
OK myślę, że na razie te kila przykładów wystarczy, mam w zanadrzu jeszcze kilka mini-programików, myślę że z czasem je udostępnię. Jak sami widzicie jestem jeszcze dość zielony w paradygmacie funkcyjnym, ale powoli nabieram zrozumienia wobec tej „filozofii”. Mam szczerą nadzieję, że analiza tych kilku programów pozwoli wam szybciej oswoić się z nowym językiem, a przede wszystkim paradygmatem.
Pozdrawiam PL







