Часть 1. Объектно-ориентированное программирование
Тем: 3
Тема 1. Программирование по контракту
Содержание
- Контракты кода
- Пред- и постусловия
- Операторы присваивания, композиции, ветвления, цикла
- Стратегии доказательств
- Контракты функций
- Чистые функции
- Хранимое состояние и инварианты
Примеры
zipДомашнее задание 1. Обработка ошибок
-
Добавьте в программу, вычисляющую выражения, обработку ошибок, в том числе:
- ошибки разбора выражений;
- ошибки вычисления выражений.
-
Для выражения
1000000*x*x*x*x*x/(x-1)
вывод программы должен иметь следующий вид:x f 0 0 1 division by zero 2 32000000 3 121500000 4 341333333 5 overflow 6 overflow 7 overflow 8 overflow 9 overflow 10 overflow
Результатdivision by zero
(overflow
) означает, что в процессе вычисления произошло деление на ноль (переполнение). - При выполнении задания следует обратить внимание на дизайн и обработку исключений.
- Человеко-читаемые сообщения об ошибках должны выводиться на консоль.
- Программа не должна «вылетать» с исключениями (как стандартными, так и добавленными).
Домашнее задание 2. Бинарный поиск
- Реализуйте итеративный и рекурсивный варианты бинарного поиска в массиве.
-
На вход подается целое число
x
и массив целых чиселa
, отсортированный по невозрастанию. Требуется найти минимальное значение индексаi
, при которомa[i] <= x
. -
Для
main
, функций бинарного поиска и вспомогательных функций должны быть указаны, пред- и постусловия. Для реализаций методов должны быть приведены доказательства соблюдения контрактов в терминах троек Хоара. -
Интерфейс программы.
- Имя основного класса —
search.BinarySearch
. - Первый аргумент командной строки — число
x
. - Последующие аргументы командной строки — элементы массива
a
.
- Имя основного класса —
-
Пример запуска:
java search.BinarySearch 3 5 4 3 2 1
. Ожидаемый результат:2
.
Библиография
Тема 2. Реализация ООП
Содержание
- Классы
- Инвариант класса
- Задачи инкапсуляции
- Интерфейсы
- Интерфейс как синтаксический контракт
- Интерфейс как семантический контракт
- Абстрактные базовые классы и наследование
- Устранение дублирования
- Вынос изменяемой логики в наследников
Домашнее задание 3. Очередь на массиве
-
Определите модель и найдите инвариант структуры данных
«очередь».
- Определите функции, которые необходимы для реализации очереди.
-
Найдите их пред- и постусловия, если очередь не может содержать
null
.
-
Реализуйте классы, представляющие циклическую очередь
на основе массива.
-
Класс
ArrayQueueModule
должен реализовывать один экземпляр очереди с использованием переменных класса. -
Класс
ArrayQueueADT
должен реализовывать очередь в виде абстрактного типа данных (с явной передачей ссылки на экземпляр очереди). -
Класс
ArrayQueue
должен реализовывать очередь в виде класса (с неявной передачей ссылки на экземпляр очереди). -
Должны быть реализованы следующие функции (процедуры) / методы:
enqueue
– добавить элемент в очередь;element
– первый элемент в очереди;dequeue
– удалить и вернуть первый элемент в очереди;size
– текущий размер очереди;isEmpty
– является ли очередь пустой;clear
– удалить все элементы из очереди.
- Модель, инвариант, пред- и постусловия записываются в исходном коде в виде комментариев.
- Обратите внимание на инкапсуляцию данных и кода во всех трех реализациях.
-
Класс
- Напишите простые тесты к реализованным классам.
Домашнее задание 4. Очереди
-
Определите интерфейс очереди
Queue
и опишите его контракт. -
Реализуйте класс
LinkedQueue
— очередь на связном списке. -
Выделите общие части классов
LinkedQueue
иArrayQueue
в базовый классAbstractQueue
.
Это домашнее задание связано с предыдущим.
Примеры
zipЭкзаменационные вопросы
- Пре- и постусловия, инварианты
- Интерфейсы
- Абстрактные базовые классы
- Принцип подстановки Лисков
Практические навыки
- Реализация программ на Java с применением интерфейсов и абстрактных базовых классов
Тема 3. Generics
Содержание
- Введение в Generics
- Полиморфизм и его типы
- Generics и templates
- Применение Generics
- Реализация Generics
- Wildcards и ограниченные wildcards
- Параметры типов и ограниченные параметры типов
- Ограничения Generics и reifables
- Generics и вариантность
- Ко- и контрвариантность
- Источники и приемники
- Правило выбора extends и super
- Смешение Generic и не Generic кода
- Стирание информации о типе и сырые типы
- Добавление информации о типе и UncheckedWarning
Домашнее задание 5. Вычисление в различных типах
Добавьте в программу разбирающую и вычисляющую выражения трех переменных поддержку вычисления в различных типах.
Создайте класс
expression.generic.GenericTabulator
, реализующий интерфейсexpression.generic.Tabulator
:public interface Tabulator { Object[][][] tabulate( String mode, String expression, int x1, int x2, int y1, int y2, int z1, int z2 ) throws Exception; }
Аргументы
mode
— режим работыРежим Тип i
int
с детекцией переполненийd
double
bi
BigInteger
expression
— вычисляемое выражение;x1
,x2
;y1
,y2
;z1
,z2
— диапазоны изменения переменных (включительно).
Возвращаемое значение — таблица значений функции, где
R[i][j][k]
соответствуетx = x1 + i
,y = y1 + j
,z = z1 + k
. Если вычисление завершилось ошибкой, в соответствующей ячейке должен бытьnull
.-
Доработайте интерфейс командной строки:
-
Первым аргументом командной строки программа должна принимать указание
на тип, в котором будут производится вычисления:
Опция Тип -i
int
с детекцией переполнений-d
double
-bi
BigInteger
- Вторым аргументом командной строки программа должна принимать выражение для вычисления.
- Программа должна выводить результаты вычисления для всех целочисленных значений переменных из диапазона −2..2.
-
Первым аргументом командной строки программа должна принимать указание
на тип, в котором будут производится вычисления:
- Реализация не должна содержать непроверяемых преобразований типов.
-
Реализация не должна использовать аннотацию
@SuppressWarnings
. - При выполнении задания следует обратить внимание на простоту добавления новых типов и операций.
Часть 2. Введение в JavaScript
Тем: 3
Тема 4. Функции
Содержание
- JavaScript и Java
- Появление и история JavaScript/ECMAScript
- Связь с Java
- Различия с Java
- Strict mode
- Переменные и типы
- Объявление переменных
- Типы значений
- Массивы
- Простые функции
- Синтаксис объвления
- Передача аргументов
- Способы вызова
- Стрелочные функции
- Функции высших порядков
- Примеры
- Сортировка
- Компараторы
- Составные компараторы
- Функциональные интерфейсы
- Комбинаторы
- foldLeft, foldRight
- map
- Композиция
- Карринг
- Примеры
Домашнее задание 6. Функциональные выражения на JavaScript
-
Разработайте функции
cnst
,variable
,add
,subtract
,multiply
,divide
,negate
для вычисления выражений с тремя переменными:x
,y
иz
. -
Функции должны позволять производить вычисления вида:
let expr = subtract( multiply( cnst(2), variable("x") ), cnst(3) ); println(expr(5, 0, 0));
При вычислении выражения вместо каждой переменной подставляется значение, переданное в качестве соответствующего параметра функцииexpr
. Таким образом, результатом вычисления приведенного примера должно быть число 7. -
Тестовая программа должна вычислять выражение
x2−2x+1
, дляx
от 0 до 10. - Сложный вариант. Требуется дополнительно написать функцию
parse
, осуществляющую разбор выражений, записанных в обратной польской записи. Например, результатомparse("x x 2 - * x * 1 +")(5, 0, 0)
должно быть число76
. -
При выполнении задания следует обратить внимание на:
- Применение функций высшего порядка.
- Выделение общего кода для операций.
Тема 5. Объекты и замыкания
Содержание
- Объекты
- Объекты как ассоциативные массивы
- Свойства
- Изменение свойств
- Неопределенные свойства
- Строки как индексы
- Сокращенная запись
- Проверка наличия свойства
- Перечисление свойств
- Наследование
- Создание объектов (Object.create)
- Получение прототипа (Object.getPrototypeOf)
- Наследование свойств
- Переопределение свойств
- Удаление свойств
- Методы
- Функции в свойствах
- Наследование функций
- Aliasing
- Неявная передача this
- Явная передача this
- Конструкторы
- Фабрики
- Конструкторы
- Прототипы в конструкторах
- Явное создание объекта и вызов конструктора
- Получение конструктора
- Объекты как ассоциативные массивы
- Замыкания
- Хранение состояния в замыкании
- Замыкание изменяемых переменных
- Трюк с объявлением промежуточной функции
- Общее состояние нескольких функций
- Модули
- Определение модуля
- Определение конструкторов
- Определение функций
- Использования модуля
- Прямое использование
- Импортирование
- Переменные класса
- Определение модуля
Домашнее задание 7. Объектные выражения на JavaScript
-
Разработайте классы
Const
,Variable
,Add
,Subtract
,Multiply
,Divide
,Negate
для представления выражений с тремя переменными:x
,y
иz
.-
Пример описания выражения
2x-3
:let expr = new Subtract( new Multiply( new Const(2), new Variable("x") ), new Const(3) ); println(expr.evaluate(5, 0, 0));
-
При вычислении такого выражения вместо каждой переменной
подставляется её значение, переданное в качестве аргумента
метода
evaluate
. Таким образом, результатом вычисления приведенного примера должно стать число 7. -
Метод
toString()
должен выдавать запись выражения в обратной польской записи. Например,expr.toString()
должен выдавать «2 x * 3 -
».
-
Пример описания выражения
-
Функция
parse
должна выдавать разобранное объектное выражение. - Сложный вариант.Метод
diff("x")
должен возвращать выражение, представляющее производную исходного выражения по переменнойx
. Например,expr.diff("x")
должен возвращать выражение, эквивалентноеnew Const(2)
. Выраженияnew Subtract(new Const(2), new Const(0))
иnew Subtract( new Add( new Multiply(new Const(0), new Variable("x")), new Multiply(new Const(2), new Const(1)) ) new Const(0) )
так же будут считаться правильным ответом. - Бонусный вариант.
Требуется написать
метод
simplify()
, производящий вычисления константных выражений. Например,parse("x x 2 - * 1 +").diff("x").simplify().toString()
должно возвращать «x x 2 - +
» или аналогичное по сложности эквивалентное выражение. -
При выполнении задания следует обратить внимание на:
- Применение инкапсуляции.
- Выделение общего кода для операций.
- Минимизацию необходимой памяти.
Тема 6. Что еще есть в JavaScript
Содержание
- Обработка ошибок
- Стандартные ошибки
- Try-catch-finally
- Что можно бросить
- Пользовательские исключения
- Нет такой вещи как...
- Глобальные переменные
- Предопределенные значения
- Блочные переменные
- Реализация замыканий
- Стандартная библиотека
- Основные типы
- Основные функции
- eval
- parseInt/Float
- isNaN/Finite
- Составные типы
- Объекты
- Функции
- Массивы
- Строки
- Boolean
- Number
- Date
- RegExp
- Встроенные ошибки
- Error
- RangeError
- ReferenceError
- SyntaxError
- TypeError
- URIError
- Наборы функций
- Math
- JSON
- Классы и методы
- Свойства-методы
- Getters и setters
- Классы
- Наследование
- Javascript 6+
- Шаблонные строки
- Set и Map
- Модули
- Свойства (не рассказывалось)
- Определение свойств
- Атрибуты свойств: enumerable, writable, configurable
- Атрибуты свойств: value, get, set
- Атрибуты объектов: extensible, seal/isSealed, freeze/isFrozen
Домашнее задание 8. Обработка ошибок на JavaScript
-
Добавьте в предыдущее домашнее задание функцию
parsePrefix(string)
, разбирающую выражения, задаваемые записью вида «(- (* 2 x) 3)
». Если разбираемое выражение некорректно, методparsePrefix
должен бросать ошибки с человеко-читаемыми сообщениями. -
Добавьте в предыдущее домашнее задание метод
prefix()
, выдающий выражение в формате, ожидаемом функциейparsePrefix
. -
При выполнении задания следует обратить внимание на:
- Применение инкапсуляции.
- Выделение общего кода для операций.
- Минимизацию необходимой памяти.
- Обработку ошибок.
Часть 3. Введение в Clojure
Тем: 5
Тема 7. Функции
Содержание
- Выражения и переменные
- Константы
- Функции
- Фиксированной арности
- Произвольной арности
- Переменные
- Определение
- Функции как значения
- Примитивные типы
- Приведение типов
- Функции
- Определение функции
- Рекурсивные функции
- Общая рекурсия
- Хвостовая рекурсия
- Оптимизация хвостовой рекурсии
- Контракты
- Списки
- Литералы
- Создание
- Операции
- Проверки
- Свертки
- Вектора
- Литералы
- Создание
- Операции
- Проверки
- Свертки
- Стандартные функции
Домашнее задание 9. Линейная алгебра на Clojure
-
Разработайте функции для работы с объектами линейной алгебры,
которые представляются следующим образом:
- скаляры – числа
- векторы – векторы чисел;
- матрицы – векторы векторов чисел.
-
Функции над векторами:
v+
/v-
/v*
/vd
– покоординатное сложение/вычитание/умножение/деление;scalar
/vect
– скалярное/векторное произведение;v*s
– умножение на скаляр.
-
Функции над матрицами:
m+
/m-
/m*
/md
– поэлементное сложение/вычитание/умножение/деление;m*s
– умножение на скаляр;m*v
– умножение на вектор;m*m
– матричное умножение;transpose
– транспонирование;
- Сложный вариант.
- Ко всем функциям должны быть указаны контракты. Например, нельзя складывать вектора разной длины.
-
Все функции должны поддерживать произвольное число аргументов.
Например
(v+ [1 2] [3 4] [5 6])
должно быть равно[9 12]
.
-
При выполнении задания следует обратить внимание на:
- Применение функций высшего порядка.
- Выделение общего кода для операций.
Code Golf (бонус)
Правила
- Выигрывает самая короткая программа. Длина программы считается после удаления незначимых пробелов.
- Можно использовать произвольные функции стандартной библиотеки Clojure.
- Нельзя использовать функции Java и внешних библиотек.
-
Подача решений через
чат.
Решение должно быть корректно отформатировано
и начинаться с
;Solution номинация длина
. Например,;Solution det-3 1000
.
Номинации
det-3
— определитель матрицы за O(n³);det-s
— определитель дольше чем за O(n³);inv-3
— обратная матрица за O(n³);inv-s
— обратная дольше чем за O(n³).
Библиография
Тема 8. Внешний мир
Содержание
- Ввод-вывод
- Простейший ввод-вывод
- Работа с последовательностями событий
- Разбор ввода
- Разбор и гомоиконность
- Стандартный парсер
- Операции с кодом
- Исполнение сгенерированного кода
- Гомоиконность
- Подрядки вычисления
- Аппликативный
- Нормальный
- Ленивый
- Потоки
- Основные определения
- Операции с потоками
- Конечные потоки
- Бесконечные потоки
- Ленивые последовательности
- Отображения и множества
- Литералы
- Создание
- Проверки
- Операции
Домашнее задание 10. Функциональные выражения на Clojure
-
Разработайте функции
constant
,variable
,add
,subtract
,multiply
,divide
иnegate
для представления арифметических выражений.-
Пример описания выражения
2x-3
:(def expr (subtract (multiply (constant 2) (variable "x")) (constant 3)))
-
Выражение должно быть функцией, возвращающей
значение выражения при подстановке переменных,
заданных отображением.
Например,
(expr {"x" 2})
должно быть равно 1.
-
Пример описания выражения
-
Разработайте разборщик выражений, читающий
выражения в стандартной для Clojure форме.
Например,
(parseFunction "(- (* 2 x) 3)")
должно быть эквивалентноexpr
. - Сложный вариант.
Функции
add
,subtract
,multiply
иdivide
должны принимать произвольное число аргументов. Разборщик так же должен допускать произвольное число аргументов для+
,-
,*
,/
. -
При выполнении задания следует обратить внимание на:
- Выделение общего кода для операций.
Библиография
Тема 9. Объекты
Содержание
- JS-подобные объекты
- Ассоциативные массивы и прототипы
- Свойства
- Методы
- Конструкторы
- Наследование
- Java-объекты
- Интерфейсы
- Реализация
- Изменяемые поля
- Работа с Java-классами
- Изменяемое состояние
- Динамические переменные
- Локальные переменные
- Ссылки
Домашнее задание 11. Объектные выражения на Clojure
-
Разработайте конструкторы
Constant
,Variable
,Add
,Subtract
,Multiply
,Divide
иNegate
для представления арифметических выражений.-
Пример описания выражения
2x-3
:(def expr (Subtract (Multiply (Constant 2) (Variable "x")) (Constant 3)))
-
Функция
(evaluate expression vars)
должна производить вычисление выраженияexpression
для значений переменных, заданных отображениемvars
. Например,(evaluate expr {"x" 2})
должно быть равно 1. -
Функция
(toString expression)
должна выдавать запись выражения в стандартной для Clojure форме. -
Функция
(parseObject "expression")
должна разбирать выражения, записанные в стандартной для Clojure форме. Например,(parseObject "(- (* 2 x) 3)")
должно быть эквивалентноexpr
.
-
Пример описания выражения
- Сложный вариант.
-
Конструкторы
Add
,Subtract
,Multiply
иDivide
должны принимать произвольное число аргументов. Парсер так же должен допускать произвольное число аргументов для+
,-
,*
,/
. -
Функция
(diff expression "variable")
должна возвращать выражение, представляющее производную исходного выражения по заданной переменной. Например,(diff expression "x")
должен возвращать выражение, эквивалентное(Constant 2)
, при этом выражения(Subtract (Constant 2) (Constant 0))
и(Subtract (Add (Multiply (Constant 0) (Variable "x")) (Multiply (Constant 2) (Constant 1))) (Constant 0))
так же будут считаться правильным ответом.
-
Конструкторы
- При выполнении задания можно использовать любой способ представления объектов.
- При выполнении задания можно использовать функции, для определения JS-like объектов, приведённые на лекции.
Библиография
- Clojure
- Clojure Cheat Sheet
- Daniel Higginbotham Clojure for the Brave and True (Chapters 10, 12)
Тема 10. Комбинаторные парсеры
Содержание
- Базовые концепции
- Результат разбора
- Интерфейс парсера
- Простейшие парсеры
- Простейшие комбинаторы парсеров
- Комбинаторы
- Вспомогательные методы
- Последовательности
- Альтернативы
- Регулярные замыкания
- Пример: JSON
- Простые парсеры
- Массивы
- Объекты
- Полный парсер
Домашнее задание 12. Комбинаторные парсеры
- Простой вариант.
Реализуйте функцию
(parseObjectPostfix "expression")
, разбирающую выражения, записанные в постфиксной форме, и функциюtoStringPostfix
, возвращающую строковое представление выражения в этой форме. Например,(toStringPostfix (parseObjectPostfix "( ( 2 x * ) 3 - )"))
должно возвращать((2 x *) 3 -)
. - Сложный вариант.
Реализуйте функцию
(parseObjectInfix "expression")
, разбирающую выражения, записанные в инфиксной форме, и функциюtoStringInfix
, возвращающую строковое представление выражения в этой форме. Например,(toStringInfix (parseObjectInfix "2 * x - 3"))
должно возвращать((2 * x) - 3)
. - Бонусный вариант. Добавьте в библиотеку комбинаторов возможность обработки ошибок и продемонстрируйте ее использование в вашем парсере.
- Функции разбора должны базироваться на библиотеке комбинаторов, разработанной на лекции.
Библиография
Тема 11. Макросы и основания информатики
Содержание
- Макросы
- Генерация кода
- Синтаксические кавычки
- Пример: JS-подобные объекты
- Пример: разбор текста
- Кодирование Чёрча
- Булева алгебра
- Пары и списки
- Персистентная память
- Числа Чёрча
- Натуральные числа
- Арифметика
- Предикаты сравнения
- Числа со знаком
- Дальнейшие обобщения
Библиография
- Daniel Higginbotham Clojure for the Brave and True (Chapter 8)
- Yehonathan Sharvit Numbers and Arithmetics with functions only
- Yehonathan Sharvit Boolean Algebra
Часть 4. Введение в Prolog
Тем: 3
Тема 12. Факты, правила и вычисления
Содержание
- Факты и правила
- Термы
- Атомы
- Числа
- Структуры
- Факты
- Объявление
- Переменные
- Запросы
- Правила
- Объявление
- Простые
- Конъюнкция
- Дизъюнкция
- Отрицание
- Рекурсия
- Запросы
- Унификация
- Порядок выполнения
- Возвраты и отсечения
- Объявление
- Термы
- Вычисления
- Операторы и функции
- Рекурсивные вычисления
- Мемоизация
- Обратимые вычисления
- Списки
- Синтаксис
- Сопоставление с образцом
- Правила на списках
- Правила высшего порядка
Домашнее задание 13. Простые числа на Prolog
Разработайте правила:
prime(N)
, проверяющее, чтоN
– простое число.composite(N)
, проверяющее, чтоN
– составное число.prime_divisors(N, Divisors)
, проверяющее, что списокDivisors
содержит все простые делители числаN
, упорядоченные по возрастанию. ЕслиN
делится на простое числоP
несколько раз, тоDivisors
должен содержать соответствующее число копийP
.
Варианты
- Простой:
N
≤ 1000. - Сложный:
N
≤ 105. - Бонусный:
N
≤ 107.
- Простой:
-
Вы можете рассчитывать, на то, что до первого запроса будет
выполнено правило
init(MAX_N)
.
Тема 13. Задачи, унификация и объекты
Содержание
- Задачи
- Задача о расстановке ферзей
- Загадка Эйнштейна
- Унификация и объекты
- Унификация
- Определение
- Наследование
- Мультиметоды
Домашнее задание 14. Деревья поиска на Prolog
- Реализуйте ассоциативный массив (map) на основе деревьев поиска. Для решения можно реализовать любое дерево поиска логарифмической высоты.
Простой вариант. Разработайте правила:
map_build(ListMap, TreeMap)
, строящее дерево из упорядоченного списка пар ключ-значение (O(n));map_get(TreeMap, Key, Value)
, проверяющее, что массив содержит заданную пару ключ-значение (O(log n)).
Сложный вариант. Дополнительно разработайте правила:
map_put(TreeMap, Key, Value, Result)
; добавляющее пару ключ-значение в массив, или заменяющее текущее значение для ключа (O(log n));map_remove(TreeMap, Key, Result)
удаляющее отображение для ключа (O(log n));map_build(ListMap, TreeMap)
, строящее дерево из неупорядоченного списка пар ключ-значение (O(n log n)).
Тема 14. Разбор текста
Содержание
- Термы
- Преобразование в терм
- Обратное преобразование
- Списки символов
- Преобразование в список
- Преобразование списка в атом
- Обратное преобразование
- Грамматики
- Описание грамматики
- Преобразование в строку
- Обратное преобразование
Домашнее задание 15. Разбор выражений на Prolog
-
Доработайте правило
evaluate(Expression, Variables, Result)
, вычисляющее арифметические выражения.-
Пример вычисления выражения
2*(-x)-3
дляx = 5
:evaluate( operation(op_subtract, operation(op_multiply, const(2), operation(op_negate, variable(x)) ), const(3) ), [(x, 5)], -13 )
-
Поддерживаемые операции:
сложение (
op_add
,+
), вычитание (op_subtract
,-
), умножение (op_multiply
,*
), деление (op_divide
,/
), противоположное число (op_negate
,negate
).
-
Пример вычисления выражения
- Простой вариант.
Реализуйте правило
prefix_str(Expression, Atom)
, разбирающее/выводящее выражения, записанные в префиксной форме. Например,prefix_str( operation(op_subtract, operation(op_multiply, const(2), operation(op_negate, variable(x))), const(3) ), '(- (* 2 (negate x)) 3)' )
- Сложный вариант.
Реализуйте правило
infix_str(Expression, Atom)
, разбирающее/выводящее выражения, записанные в полноскобочной инфиксной форме. Например,infix_str( operation(op_subtract, operation(op_multiply, const(2), operation(op_negate, variable(x))), const(3) ), '((2 * negate x) - 3)' )
- Правила должны быть реализованы с применением DC-грамматик.