Programowanie. Lista zadań nr 15. Na ćwiczenia 11, 19 i 23 czerwca 2008



Podobne dokumenty
Programowanie funkcyjne Wykład 13. Siła wyrazu rachunku lambda

Programowanie 2009 Programming 2009

Wykład 2: Rachunek lambda

Programowanie funkcyjne. Wykªad 13

Szablony funkcji i szablony klas

Algorytmy funkcjonalne i struktury danych

Programowanie obiektowe i C++ dla matematyków

P. Urzyczyn: Materia ly do wyk ladu z semantyki. Uproszczony 1 j. ezyk PCF

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Programowanie Funkcyjne. Marcin Kubica Świder,

Typy, klasy typów, składnie w funkcji

Teoretyczne Podstawy Języków Programowania Wykład 4. Siła wyrazu rachunku λ

Poprawność semantyczna

Języki i techniki programowania Ćwiczenia 2

Podstawy Programowania C++

Język programowania zbiór reguł określających, które ciągi symboli tworzą program komputerowy oraz jakie obliczenia opisuje ten program.

Paradygmaty programowania

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Obiektowy Caml. Paweł Boguszewski

java.util.* :Kolekcje Tomasz Borzyszkowski

Przeciążenie operatorów

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Wykład 3 Składnia języka C# (cz. 2)

Język programowania Scala / Grzegorz Balcerek. Wyd. 2. Poznań, cop Spis treści

KOTLIN. Język programowania dla Androida

Podstawy programowania skrót z wykładów:

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie obiektowe

Składnia funkcji i Rekurencja w języku Haskell

Metody Kompilacji Wykład 3

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Wstęp do Programowania potok funkcyjny

Przeciążanie operatorów

Informatyka 1. Wyrażenia i instrukcje, złożoność obliczeniowa

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Wykład 4: Klasy i Metody

Wiadomości wstępne Środowisko programistyczne Najważniejsze różnice C/C++ vs Java

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Typy danych, zmienne i tablice. Tomasz Borzyszkowski

Wprowadzenie. Organizacja pracy i środowisko programistyczne. Mirosław Ochodek

Wstęp do Programowania potok funkcyjny

Język ludzki kod maszynowy

Programowanie w C++ Wykład 6. Katarzyna Grzelak. 1 kwietnia K.Grzelak (Wykład 6) Programowanie w C++ 1 / 43

3. Wykład 3: Dowody indukcyjne, strategie dowodowe Dowody indukcyjne. Dotychczas zobaczyliśmy w jaki sposób można specyfikować definicje

Python wstęp do programowania dla użytkowników WCSS

Dziedziczenie Dana jest klasa Punkt w pliku o nazwie Punkt.java:

STL: Lekcja 1&2. Filozofia STL

Wstęp do Programowania potok funkcyjny

Paradygmaty programowania. Paradygmaty programowania

SWIFT. Zaawansowane Programowanie Obiektowe

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Algorytmy i struktury danych. wykład 1

Czym jest stos i sterta?

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

- nawiasy kwadratowe oznaczają, że to lista

Operacje wykonywane są na operandach (argumentach operatorów). Przy operacji dodawania: argumentami operatora dodawania + są dwa operandy 2 i 5.

Programowanie 2. Język C++. Wykład 3.

Wykład 11a. Składnia języka Klasycznego Rachunku Predykatów. Języki pierwszego rzędu.

Podstawy Programowania Obiektowego

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

PARADYGMATY PROGRAMOWANIA Wykład 4

Programowanie w C++ Wykład 7. Katarzyna Grzelak. 23 kwietnia K.Grzelak (Wykład 7) Programowanie w C++ 1 / 40

Programowanie obiektowe

Wykład 2 Składnia języka C# (cz. 1)

Kurs WWW. Paweł Rajba.

Elementy języka Haskell

Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory

Rozdział 4 KLASY, OBIEKTY, METODY

Klasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C

Problem Próby rozwiązania Maszyna stanów Inne zastosowania Podsumowanie. Maszyny stanów. Programowanie gier bez Unity, cz. 3.

Myśl w języku Python! : nauka programowania / Allen B. Downey. Gliwice, cop Spis treści

C++ Przeładowanie operatorów i wzorce w klasach

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Przykładowy dokument XML

Zaawansowane programowanie w języku C++ Przeciążanie operatorów

Drzewa BST i AVL. Drzewa poszukiwań binarnych (BST)

DECLARE <nazwa_zmiennej> typ [(<rozmiar> )] [ NOT NULL ] [ { := DEFAULT } <wartość> ];

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

1 Podstawy c++ w pigułce.

Algorytmy i Struktury Danych. Anna Paszyńska

Prezentacja o Haskell u(rozdział 3 i 4)

Diagramy klas. dr Jarosław Skaruz

C# 6.0 : kompletny przewodnik dla praktyków / Mark Michaelis, Eric Lippert. Gliwice, cop Spis treści

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Zmienne, stałe i operatory

Programowanie obiektowe

Spis treści. Wprowadzenie 15

1 Podstawy c++ w pigułce.

Wstęp do programowania obiektowego, wykład 7

Język C zajęcia nr 11. Funkcje

Wstęp do Programowania 2

Luty 2001 Algorytmy (7) 2000/2001

Oracle PL/SQL. Paweł Rajba.

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Wstęp do Programowania potok funkcyjny

Transkrypt:

Programowanie Lista zadań nr 15 Na ćwiczenia 11, 19 i 23 czerwca 2008 Zadanie 1. Pokaż, że w systemie z polimorfizmem parametrycznym można napisać program P n rozmiaru O(n), którego typ ma rozmiar 2 2Ω(n). Pokaż, że typ wyrażenia rozmiaru n w systemie z polimorfizmem parametrycznym ma rozmiar 2 2O(n). Zadanie 2. Wyznacz typ główny σ i napisz dowód sądu typowego w polimorficznym systemie typów Damasa-Milnera: let f = λx.x in ff end : σ Zadanie 3. Rozważmy system, w którym konstrukcja α.σ nie jest schematem typu, lecz zwykłym typem, tj. język, którego abstrakcyjna składnia jest następująca: e ::= x e 1 e 2 λx.e σ ::= α σ 1 σ 2 α.σ i w którym przyjęto następujące reguły typowania: Γ, x : σ x : σ Γ e : σ Γ e : α.σ α FV(Γ) Γ e 1 : σ τ Γ e 2 : σ Γ e 1 e 2 : τ Γ e : α.σ Γ e : σ[α/τ] Γ, x : σ e : τ Γ λx.e : σ τ Jest to tak zwany rachunek typów drugiego rzędu lub system F. Pokaż, że w tym systemie wyrażenie λx.xx posiada typ, podczas gdy w języku z tzw. płytkim polimorfizmem, tj. w systemie Damasa-Milnera nie. Wskaż przykład termu, który nie posiada typu w nowym systemie. Pokaż, że każdy term, który posiada typ w prostym systemie typów posiada go i w nowym. Pokaż, że jeżeli do składni wyrażeń dodać let i przyjąć w systemie F tłumaczenie Landina, to każdy let-term typowalny w ML-u ma też typ w systemie F z tłumaczeniem Landina (zatem let jest jedynie cukrem syntaktycznym w monomorficznym systemie typów i w systemie F, lecz ma kluczowe znaczenie dla polimorfizmu w ML-u). 1

Zadanie 4. Rozważmy system z poprzedniego zadania. Zauważ, że istnieją dokładnie dwa zamknięte termy typu α.α α α. Typ ten może więc służyć do zakodowania typu bool. Zdefiniuj wartości true i false oraz komplet operacji logicznych. Zauważ, że wszystkie dają się wyrazić przy pomocy operatora if i że operator ten jest kodowany przez wyrażenie λx.x (to nie przypadek). Pamiętając o liczebnikach Churcha zauważ dalej, że α.(α α) (α α) może reperezentować typ nat. Pokaż, że dowolny zamknięty term jest typu α.(α α) (α α), wtedy i tylko wtedy, gdy jest liczebnikiem Churcha. Zdefiniuj podstawowe operacje arytmetyczne. Zauważ, że wszystkie dają się wyrazić przy pomocy iteratora iter, takiego, że iter n f c = f n (c). Zauważ, że iter jest kodowany przez wyrażenie λx.x (to nie przypadek). Zauważ dalej, że typ list(β) α.(β α α) (α α) koduje listy typu β. Zdefiniuj konstruktory i operacje działające na listach. Zauważ, że dają się one wyrazić przy pomocy iteratora foldr i że foldr jest kodowany przez wyrażenie λx.x (to nie przypadek). Wywnioskuj z tych rozważań, że system F może służyć do zadania semantyki typów danych, takich, jak listy, krotki, liczby itp. Zakoduj kilka innych typów danych (unit, void, drzewa binarne itp.). Zadanie 5. Pokaż, że polimorfizm parametryczny kłóci się ze skutkami ubocznymi. Rozważmy język t ::= x t 1 t 2 λx.t let x = t 1 in t 2 n t 1 + t 2 True False ref t t 1 := t 2! t τ ::= α τ 1 τ 2 Int Bool Ref τ σ ::= α.τ z regułami typowania Γ, x : α.τ x : τ[ α/ τ ] Γ t : τ 1 τ 2 Γ s : τ 2 Γ ts : τ 2 Γ, x : τ 1 t : τ 2 Γ λx.t : τ 1 τ 2 Γ t 1 : τ 1 Γ, x : α.τ 1 t 2 : τ 2 let x = t 1 in t 2 : τ 2 α = FV(τ 1 ) \ FV(Γ) Γ n : Int Γ t 1 : Int Γ t 2 : Int Γ t 1 + t 2 : Int Γ True : Bool Γ False : Bool Γ t : τ Γ ref t : Ref τ Γ t 1 : Ref τ Γ t 2 : τ Γ t 1 := t 2 : τ Γ t : Ref α Γ! t : α Operator ref alokuje pamięć dla nowej zmiennej i inicjuje ją podaną wartością, := jest operatorem przypisania, a! dereferencji. Np. program let x = ref 1 in x := 2 alokuje pamięć dla komórki przechowującej dane typu Int, związuje adres tej komórki ze zmienną x typu Ref Int, inicjuje tę komórkę wartością 1, a następnie przypisuje jej wartość 2. Pokaż, że powyższy system jest sprzeczny i pozwala napisać program, który dodaje 1 do True. Wykorzystaj ten trik do zdefiniowania funkcji cast : α β. 2

Komentarz: Istnieje wiele rozwiązań tego problemu, żadne jednak nie jest eleganckie. Konserwatywne rozszerzenie systemu Damasa-Milnera wymaga wprowadzenia dodatkowych zmiennych typowych (tzw. słabych typów) i mało intuicyjnych reguł typowania. Prostsze rozwiązanie (Andrew Wrighta) uszkadza system typów tak, że przestaje być dla niego słuszne twierdzenie o subject reduction dla reguły η. W Haskellu problem znika, bo nie ma skutków ubocznych (choć pojawia się dla funkcji unsafeperformio i nie jest dla niej w żaden sposób rozwiązany funkcja ta pozwala zdefiniować funkcję cast : α β). Zadanie 6. Pokaż, że w języku z poprzedniego zadania można przywrócić niesprzeczność jeśli wprowadzimy nowy rodzaj zmiennych, nazwijmy je słabymi i oznaczmy ich zbiór przez W. Zmienne te nie mogą wystąpić w schemacie typu po kwantyfikatorze, tj. nie wolno ich generalizować w regule let nawet, jeśli nie występują w Γ. Warunek w regule let ma więc postać α = FV(τ 1 ) \ (FV(Γ) X ). Przyjmij, że typy mają teraz postać (Weak α 1,..., Weak α n ) τ w której prefiks wskazuje, które zmienne są słabe. Zadanie 7. Zauważ, że rekonstrukcja typów z polimorfizmem parametrycznym kłóci się z przeciążaniem operatorów pokaż że w następującym języku: z regułami typowania t ::= x t 1 t 2 λx.t let x = t 1 in t 2 n r t 1 + t 2 τ ::= α τ 1 τ 2 Int Float σ ::= α.τ Γ, x : α.τ x : τ[ α/ τ ] Γ t : τ 1 τ 2 Γ s : τ 2 Γ ts : τ 2 Γ, x : τ 1 t : τ 2 Γ λx.t : τ 1 τ 2 Γ t 1 : τ 1 Γ, x : α.τ 1 t 2 : τ 2 let x = t 1 in t 2 : τ 2 α = FV(τ 1 ) \ FV(Γ) Γ n : Int Γ r : Float Γ t 1 : Int Γ t 2 : Int Γ t 1 + t 2 : Int Γ t 1 : Float Γ t 2 : Float Γ t 1 + t 2 : Float istnieją programy nie posiadające typu głównego. Jaki wpływ ma brak typu głównego na efektywność rekonstrukcji typów i możliwość rozdzielnej kompilacji? Zadanie 8. Pokaż, że w języku z poprzedniego zadania można przywrócić istnienie typów głównych, jeżeli wprowadzimy dodatkowy rodzaj zmiennych, nazwijmy je numerycznymi, a ich zbiór oznaczmy przez N. Pod zmienne te wolno podstawić jedynie stałe Int oraz Float. Przyjmij, że typy mają teraz postać (Num α 1,..., Num α n ) τ w której prefiks wskazuje, które zmienne są numeryczne. Zauważ, że jesteśmy o krok od wynalezienia haskellowych klas typów. 3

Zadanie 9. Zauważ, że algebraiczne typy danych świetnie współgrają z polimorfizmem parametrycznym deklaracja data T α = C 1 τ 1 1... τ n 1 1... C k τ 1 k... τ n k k dodaje po prostu do składni termów stałe C 1,..., C k i wyrażenie case pozwalające dopasowywać wyrażenia do wzorców, do typów wyrażenie typowe T τ 1... τ k, a do reguł typowania reguły Γ C i : τ 1 i... τ n i i T α Zdefiniuj składnię abstrakcyjną i napisz algorytm rekonstrukcji typów dla takiego języka. Zauważ, że musimy przyjąć następujące założenie: n i j=1 FV(τ j i ) α, inaczej system jest sprzeczny pokaż, że jeśli dopuścilibyśmy deklarację data T = C a to łatwo moglibyśmy napisać funkcję cast :: a -> b. (Tu jesteśmy o krok od wynalezienia typów egzystencjalnych). Zadanie 10. Zauważ, że rekursja polimorficzna nie jest zjawiskiem egzotycznym lecz pojawia się w całkiem naturalnych problemach. Lista o bezpośrednim dostępie, to struktura danych udostępniająca operacje: class RandomAccessList l where nil :: l a cons :: a -> l a -> l a head :: l a -> a tail :: l a -> l a lookup :: Int -> l a -> a update :: a -> Int -> l a -> l a Wszystkie operacje powinny się wykonywać w czasie logarytmicznym względem wielkości listy. Jedną z możliwych implementacji takiej listy jest data Tree a = Node (Tree a, Tree a) Leaf a type BinomialRAL a = [Tree a] przy czym elementami listy [Tree a] są pełne drzewa binarne, a ich wysokości ściśle rosną. Powyższa reprezentacja jest nadmiarowa, gdyż wiele danych typu BinomialRAL jest nielegalnych. Aby system typów wykluczył nielegalne reprezentacje, powinniśmy tak zdefiniować typ Tree, by jedynymi danymi tego typu były drzewa pełne. Możemy to zrobić np. tak: 4

data Tree a = Node (Tree (a,a)) Leaf a (zauważ, że zmiana polega na zamianie miejscami typów Tree i (,) w argumencie konstruktora Node). Zaprogramuj funkcje height :: Tree a -> Int size :: Tree a -> Int peek :: Int -> Int -> Tree a -> a poke :: Int -> Int -> a -> Tree a -> Tree a link :: (Tree (a,a)) -> (Tree (a,a)) -> Tree a Funkcja peek h i t ujawnia i-ty element drzewa wysokości h (elementy numerujemy od lewej do prawej poczynając od zera), funkcja poke zmienia odpowiedni element, zaś link łączy dwa drzewa w większe. Wyjaśnij w których miejscach pojawia się rekursja polimorficzna. Komentarz: możemy w Haskellu zaprogramować typ BinomialRAL tak, że każda dana tego typu jest nie tylko ciągiem pełnych drzew, ale także wysokości tych drzew są ciągiem ściśle rosnącym. Zamiast standardowego typu [] należy zdefiniować wersję list sprawdzających rozmiar drzew. Zadanie 11. Tzw. zagnieżdżone lub nieregularne typy danych są atrakcyjne o tyle, że nie wymagają rozszerzania systemu typów. Są jednak mało intuicyjne. Lepiej byłoby majstrować przy wyniku, a nie argumencie konstruktora. To prowadzi nas do tzw. uogólnionych algebraicznych typów danych. Niestety zawierają one w sobie typy egzystencjalne, więc jak widzieliśmy w zadaniu 9 musimy uważać, żeby nie załamać systemu typów. Pozwalamy, by typ wyniku konstruktora nie był dokładnie równy definiowanemu typowi, lecz mógł być jego instancją. Ten pomysł w połączeniu z typami fantomowymi (typami, które nie posiadają wartości) prowadzi do znacznie czytelniejszej implementacji pełnych drzew binarnych: data Zero data Succ n data Tree h a where Node :: Tree h a -> Tree h a -> Tree (Succ h) a Leaf :: a -> Tree Zero a Dodatkowy parametr typowy zlicza wysokość drzewa i zapewnia, że łączymy tylko drzewa tej samej wysokości. Zaprogramuj funkcje z poprzedniego zadania dla tej reprezentacji (zauważ, że np. link jest nie tylko prostsza, ale ma znacznie lepszą złożoność). Zauważ, że rekursja polimorficzna tu również jest niezbędna do rozwiązania zadania. 5