Функциональное программирование — различия между версиями
Shersh (обсуждение | вклад) (→Кр2) |
Shersh (обсуждение | вклад) (→Кр2: добавлен разбор кр2) |
||
Строка 118: | Строка 118: | ||
* [https://pp.vk.me/c625826/v625826822/9174/QRhQIqwNX5Q.jpg] | * [https://pp.vk.me/c625826/v625826822/9174/QRhQIqwNX5Q.jpg] | ||
− | Разбор будет по фоткам 4 | + | Разбор будет по фоткам 3, 4, 5 (остальные задания аналогичны): |
== N1. Порядок редуцирования == | == N1. Порядок редуцирования == | ||
Строка 131: | Строка 131: | ||
Лего проверить, что fst (pair a b) = a, подставив и сделав редукции. | Лего проверить, что fst (pair a b) = a, подставив и сделав редукции. | ||
+ | |||
+ | == E1. Превратить let-биндинги в один большой лямбда-терм. == | ||
+ | |||
+ | Конструкция | ||
+ | |||
+ | '''let''' x = z '''in''' y | ||
+ | |||
+ | превращается в | ||
+ | |||
+ | (\x . y) z | ||
+ | |||
+ | А пример просто превратится в | ||
+ | |||
+ | (\foo. [main]) [foo] | ||
+ | |||
+ | где [foo] {{---}} тело foo, [main] {{---}} тело main. | ||
+ | |||
+ | == E2. let-биндинги но с возможной взаимной рекурсией == | ||
+ | |||
+ | ): | ||
+ | |||
+ | == N2. Раскрыть, как в E1 и нормализовать == | ||
+ | |||
+ | В общем, в задании всё сказано. Надо превратить в один большой терм как в E1, а затем нормализовать, как в задании из первой кр. | ||
+ | |||
+ | == S1. Расписать систему уравнений типов == | ||
+ | |||
+ | Как в первой кр. | ||
+ | |||
+ | == TP1. Убрать сокращения и расставить скобки == | ||
+ | |||
+ | Именно это и требуется сделать. Разве что там вместо тела абстракции расписан её тип. А (->) в типе в отличие от аппликации правоассоциативна, то есть в | ||
+ | |||
+ | a -> b -> c | ||
+ | |||
+ | скобки ставятся следующим образом: | ||
+ | |||
+ | a -> (b -> c) | ||
+ | |||
+ | Итого: | ||
+ | * дано: (\ a b . b -> b -> a) x | ||
+ | * получается: (\ a . (\ b . b -> (b -> a))) x // вроде бы тут как раз весь тип внутри не надо заключать в скобки | ||
+ | |||
+ | == TF1. Составить терм по типу == | ||
+ | |||
+ | Тут надо пользоваться логикой. Вроде бы во всех примерах можно решить методом пристального взгляда. Мотивация: чтобы решение системы уравнений типов совпадало с полученным типом. Но в некоторых случаях довольно трудно (или даже невозможно) придумать терм по типу, например здесь не придумывается: | ||
+ | |||
+ | (a -> b) -> b -> a | ||
+ | |||
+ | === Решение === | ||
+ | |||
+ | Дано: forall a b c . (b -> c -> a) -> (c -> b) -> c -> a | ||
+ | |||
+ | Ответ: \f g c . f (g c) c | ||
+ | |||
+ | == A1. Закодировать типы по Чёрчу (без взаимной рекурсии) == | ||
+ | |||
+ | <code> | ||
+ | '''data''' Doctor a = Minute a | Maybe a a a | ||
+ | '''data''' Hour a b = Hour (Hour b b) (Doctor a) (Doctor b) | Roll b (Doctor a) | ||
+ | </code> | ||
+ | |||
+ | === Решение === | ||
+ | У каждого типа есть <tex> N \geqslant 1</tex> конструктов, а у каждого конструктора есть <tex> K \geqslant 0 </tex> аргументов. | ||
+ | |||
+ | Фиксируем тип с <tex> N </tex> конструкторами. Каждый конструктор <tex> C_i </tex> этого типа превращается в абстракцию, в которой сначала идут <tex> K_i </tex> переменных {{---}} аргументы конструктора, а потом <tex> N </tex> переменных, отвечающих конструкторам. В теле просто выбирается нужный конструктор и применяется ко всем аргументам. | ||
+ | |||
+ | caseTypeName тоже является абстракцией, которая принимает сначала одну переменную, которая "выбирает" нужный конструктор, затем набор переменных в количестве числа конструкторов. В теле просто применяется первая переменная ко всем остальным. | ||
+ | |||
+ | <code> | ||
+ | <font color=green>-- сначала Doctor </font> | ||
+ | Minute = \ a . \ x y . x a | ||
+ | Maybe = \ a b c . \ x y . y a b c | ||
+ | caseDoctor = \ p . \ x y . p x y | ||
+ | <font color=green>-- теперь Hour </font> | ||
+ | Hour = \ a b c . \ x y . x a b c | ||
+ | Roll = \ a b . \ x y . y a b | ||
+ | caseHour = \ p . x y . p x y | ||
+ | </code> | ||
+ | |||
+ | Интересное наблюдение: переменная p в case является как раз нужным конструктором, в котором уже подставлены все аргументы этого конструктора. | ||
+ | |||
+ | == A2. Закодировать типы по Чёрчу (с взаимной рекурсией) == | ||
+ | |||
+ | ): | ||
+ | |||
+ | == H1. Написать Haskell-код какой-нибудь структуру данных == | ||
+ | |||
+ | * [[АВЛ-дерево]]: [http://pastie.org/private/qbiu60aetjm9zrpqzrow ссылка на pastie] | ||
+ | *: почему я не знал Haskell, когда это дерево было в лабе по дискретке на первом курсе? ;( просто списывается с конспекта один в один... | ||
+ | * [[Квадродеревья | Квадродерево]]: [http://pastie.org/private/sf1vdmrpe7ifvqgdongwq ссылка на pastie] | ||
+ | *: не совсем то, что требует Ян, но я пока не распарсил то, что он требует; возможно, более правильная версия появится позже | ||
=Кр3= | =Кр3= | ||
=Кр4= | =Кр4= |
Версия 12:13, 26 апреля 2015
Содержание
- 1 Кр1
- 2 Кр2
- 2.1 Фотки
- 2.2 N1. Порядок редуцирования
- 2.3 E0. Определить примитивные конструкции
- 2.4 E1. Превратить let-биндинги в один большой лямбда-терм.
- 2.5 E2. let-биндинги но с возможной взаимной рекурсией
- 2.6 N2. Раскрыть, как в E1 и нормализовать
- 2.7 S1. Расписать систему уравнений типов
- 2.8 TP1. Убрать сокращения и расставить скобки
- 2.9 TF1. Составить терм по типу
- 2.10 A1. Закодировать типы по Чёрчу (без взаимной рекурсии)
- 2.11 A2. Закодировать типы по Чёрчу (с взаимной рекурсией)
- 2.12 H1. Написать Haskell-код какой-нибудь структуру данных
- 3 Кр3
- 4 Кр4
Кр1
Убрать все сокращения и расставить все скобки
(λ a b . (λ c d e . e) a) (x y) y (λ f . x) y
Решение
Скобки ставятся по следующим правилам:
- тело абстракции заключается в скобки: λ x . M λ x . (M)
- аппликация левоассоциативна: a b c d ((a b) c) d
- сокращения раскрываются во вложенные лямбды (сразу с расставлением скобок): λ a b c . M λ a . (λ b . (λ c . (M)))
Важно: тело абстракции забирает всё до конца то скобки, в которую заключено
Итого: ((((λ a . (λ b . ((λ c . (λ d . (λ e . (e)))) a))) (x y)) y) (λ f . (x))) y
Привести в нормальную форму
λ a b . a (λ c . b c) a (λ d . d) a
λ a . (λ b . y) (λ c . y (y (λ d . a a a)) (x x) a)
Решение
В нормальной форме нет редукций. Если нормальная форма существует, то её можно достичь при помощи редукций нормальным порядком, а аппликативным можно и достичь.
- Уже в нормальное форме, как ни странно
- λ b . y
Нормальный порядок редукции
(λ a . y (y (y (λ b . a))) y) (x (x (x (λ c d . d) y)) x)
Здесь про стратегии редуцирования с примерами и определениями.
Нормальный порядок редуцирования — самым первым делом раскрывается самый левый самый внешний редекс. Пример не очень удачный, так в нём всего одна редукция, после которой получится: y (y (y (λ b . (x (x (x (λ c d . d) y)) x)))) y
Более показательные и содержательные примеры (во всех случаях одна редукция будет произведена):
- (λ a . a) ((λ x . x) y) (λ x . x) y
- x (λ a . ((λ x . x) y) ((λ z . z) y)) x (λ a . y ((λ z . z) y))
Аппликативный порядок редукции
Здесь ещё про стратегии редуцирования, но немного другим языком (может быть, кому-то более понятным).
Аппликативный порядок редуцирования — первым делом редуцирования самый правый самый глубокий терм. То есть сначала упрощаем "аргументы" аппликации.
Те же примеры (во всех случаях одна редукция будет произведена):
- (λ a . a) ((λ x . x) y) (λ a . a) y
- x (λ a . ((λ x . x) y) ((λ z . z) y)) x (λ a . ((λ x . x) y) y)
Ещё один для разнообразия: ((λ x . y) (λ z . t)) ((λ a b c . a b c ((λ s . t) y) (λ t . x) u) (λ x . x)) ((λ x . x x) z)
((λ x . y) (λ z . t)) ((λ a b c . a b c ((λ s . t) y) (λ t . x) u) (λ x . x)) (z z)Выписать систему уравнений типизации
(λ a . a a) (λ b c . c)
Решение
Сначала надо дать типы всем термам и подтермам, раздавая каждый раз новые буквы новым переменным и термам. А потом связать эти буквы по следующим правилам:
- если у нас абстракция (λ x . M) :: T0, x :: T1, M :: T2, то добавляем в систему T0 = T1 -> T2,
- если имеет аппликацию (M N) :: T0, M :: T1, N :: T2, то добавляем T1 = T2 -> T0
- если у нас переменная в теле абстракции встречается несколько раз и мы раздаём каждый раз ей новые буквы, то надо будет потом приравнять типы в аргументе абстракции и внутри её тела.
Итого:
(λ a . a a) (λ b c . c) :: A
(λ a . a a) :: B, (λ b c . c) :: C
a :: D, (a a) :: E
первая и вторая буквы "a" в E — a :: F, a :: G
Можем сразу расписать часть системы уравнений:
B = C -> A
B = D -> E
F = G -> E
D = F
D = G
Теперь расписываем терм с типом C (раскрыв сокращения для начала): (λ b . (λ c . c)) :: С
b :: H, (λ c . c) :: I
c :: J, c :: K
И добавляем уравнения:
C = H -> I
I = J -> K
J = K
Кодирование по Чёрчу
Выписать кайнды конструкторов типов, выписать типы конструкторов, закодировать по Чёрчу:
data Policeman a = Doctor a | Mice
data Tree a b c = Frog c | Pip (Tree a b c)
Этого задания не было в первой кр, поэтому оно будет расписано во второй. Вместо него была система уравнений типов чуть более адовая, чем в прошлом примере.
Кр2
Фотки
Разбор будет по фоткам 3, 4, 5 (остальные задания аналогичны):
N1. Порядок редуцирования
См. прошлую кр
E0. Определить примитивные конструкции
- pair = \ x y p . p x y
- fst = \r . r (\x y . x)
- snd = \r . r (\x y . y)
- fix = \f . (\x . f (x x)) (\x . f (x x))
Лего проверить, что fst (pair a b) = a, подставив и сделав редукции.
E1. Превратить let-биндинги в один большой лямбда-терм.
Конструкция
let x = z in y
превращается в
(\x . y) z
А пример просто превратится в
(\foo. [main]) [foo]
где [foo] — тело foo, [main] — тело main.
E2. let-биндинги но с возможной взаимной рекурсией
):
N2. Раскрыть, как в E1 и нормализовать
В общем, в задании всё сказано. Надо превратить в один большой терм как в E1, а затем нормализовать, как в задании из первой кр.
S1. Расписать систему уравнений типов
Как в первой кр.
TP1. Убрать сокращения и расставить скобки
Именно это и требуется сделать. Разве что там вместо тела абстракции расписан её тип. А (->) в типе в отличие от аппликации правоассоциативна, то есть в
a -> b -> c
скобки ставятся следующим образом:
a -> (b -> c)
Итого:
- дано: (\ a b . b -> b -> a) x
- получается: (\ a . (\ b . b -> (b -> a))) x // вроде бы тут как раз весь тип внутри не надо заключать в скобки
TF1. Составить терм по типу
Тут надо пользоваться логикой. Вроде бы во всех примерах можно решить методом пристального взгляда. Мотивация: чтобы решение системы уравнений типов совпадало с полученным типом. Но в некоторых случаях довольно трудно (или даже невозможно) придумать терм по типу, например здесь не придумывается:
(a -> b) -> b -> a
Решение
Дано: forall a b c . (b -> c -> a) -> (c -> b) -> c -> a
Ответ: \f g c . f (g c) c
A1. Закодировать типы по Чёрчу (без взаимной рекурсии)
data Doctor a = Minute a | Maybe a a a data Hour a b = Hour (Hour b b) (Doctor a) (Doctor b) | Roll b (Doctor a)
Решение
У каждого типа есть
конструктов, а у каждого конструктора есть аргументов.Фиксируем тип с
конструкторами. Каждый конструктор этого типа превращается в абстракцию, в которой сначала идут переменных — аргументы конструктора, а потом переменных, отвечающих конструкторам. В теле просто выбирается нужный конструктор и применяется ко всем аргументам.caseTypeName тоже является абстракцией, которая принимает сначала одну переменную, которая "выбирает" нужный конструктор, затем набор переменных в количестве числа конструкторов. В теле просто применяется первая переменная ко всем остальным.
-- сначала Doctor Minute = \ a . \ x y . x a Maybe = \ a b c . \ x y . y a b c caseDoctor = \ p . \ x y . p x y -- теперь Hour Hour = \ a b c . \ x y . x a b c Roll = \ a b . \ x y . y a b caseHour = \ p . x y . p x y
Интересное наблюдение: переменная p в case является как раз нужным конструктором, в котором уже подставлены все аргументы этого конструктора.
A2. Закодировать типы по Чёрчу (с взаимной рекурсией)
):
H1. Написать Haskell-код какой-нибудь структуру данных
- АВЛ-дерево: ссылка на pastie
- почему я не знал Haskell, когда это дерево было в лабе по дискретке на первом курсе? ;( просто списывается с конспекта один в один...
- Квадродерево: ссылка на pastie
- не совсем то, что требует Ян, но я пока не распарсил то, что он требует; возможно, более правильная версия появится позже