C
Code for Bro
@codeforbro9 подп.
29просмотров
16 марта 2024 г.
Score: 32
Сижу, читаю книгу Брагилевского "Haskell in Depth" и вот он предлагает самостоятельно разобраться в такой функции rotateMany: -- Сам пример показывает, как могла бы выглядеть -- программа для управления радаром. -- Есть тип Direction, описывающий на какие стороны -- может быть ориентирован радар. data Direction = North | East | South | West deriving (Eq, Enum, Bounded, CyclicEnum, Show) -- Поворот Радара: -- TNone - нет поворота -- TLeft - налево -- TRight - направо -- TAround - вокруг, два раза налево. data Turn = TNone | TLeft | TRight | TAround deriving (Eq, Enum, Bounded, Show) -- Функция rotate принимает тип поворота и направления, -- а возвращает новое направление после поворота радара. -- Для каждого типа представлены функции, которые описывают, -- как обработать направление при определённом повороте: -- при TNone применяется функция id, которая возвращает свой аргумент, т.е. принял North и вернули North, т.о. эмулируется отсутствие поворота; -- при TLeft применяется функция cpred, которая возвращает предыдущий элемент перечисления в том, порядке, как они объявлены, приняли North, вернули West; -- при TRight применяется функция csucc, которая возвращает следующий элемент перечисления в том, порядке, как они объявлены, приняли North, вернули East, если дошли до последнего, принял West, то вернёмся к началу и вернём North; -- при TAround применяется функция cpred . cpred, которая возвращает предыдущий элемент на 2 шага, т.к. приняли North, вернули South; rotate :: Turn -> Direction -> Direction rotate TNone = id rotate TLeft = cpred rotate TRight = csucc rotate TAround = cpred . cpred -- А вот как работает эта функция? rotateMany :: Direction -> [Turn] -> Direction rotateMany = foldl (flip rotate) Если в кратце, то foldl принимает некую функцию, стартовое значение (Direction), и то, что может быть свёрнуто (последовательно вычисленно), в нашем случае это список поворотов ([Turn]) и в результате функция вернёт полученное направление. Т.е. вот такой пример: foldl (flip rotate) North [TRight, TRight, TAround] -- ^ список поворотов -- ^ начальное значение -- ^ функция, которая будет применяться. Начали в точке North, повернули направо (East), ещё раз направо (South), а потом кругом, т.е. 2 раза налево (North). flip rotate - это карированная функция (частично применённая, т.е. функция, часть аргументов которой инициализировали, и получили новую функцию, которая ожидает оставшихся аргументов), тип функции flip: flip :: (a -> b -> c) -> b -> a -> c Она принимает функцию 2 аргументов (a -> b -> c, a - первый аргумент, b - второй, c - результат) и ещё 2 аргумента в другом порядке по отношению к функции первого аргумента: -- Нормальное применение функции: > rotate TRight North East -- Аргументы перевёрнуты с помощью flip: > (flip rotate) North TRight East Если мы почитаем документацию по функции foldl, то мы найдём, как именно применяются аргументы при вычислении: foldl f z [x1, x2, ..., xn] == (...((z f x1) f x2) f...) f xn Исходя из этой подсказки, мы можем выполнить редукцию (вычисление) для следующего выражения: foldl (flip rotate) North [TRight, TRight, TAround] == ((North flip rotate TRight) flip rotate TRight) flip rotate TAround == TAround rotate (TRight rotate (TRight rotate North)) == rotate TAround (rotate TRight (rotate TRight North)) == rotate TAround (rotate TRight East) == rotate TAround South == North
29
просмотров
3512
символов
Нет
эмодзи
Нет
медиа

Другие посты @codeforbro

Все посты канала →