Общим в последнее время является машина Мили. Рассмотрим бесконечный поток
data Stream a = Stream a (Stream a)
теперь мы можем писать бесконечные потоки, которые могут потребляться, как [1..]
oneUpTo :: Stream Int
oneUpTo = go 1 where go n = Stream n (go (n+1))
но иногда это полезно писать потоки, которые могут быть затронуты входом, а также. Для этого мы спрячем следующий «шаг» потока позади функции
data Mealy b a = Mealy (b -> (a, Mealy b a))
И теперь мы можем написать несколько более экзотические ответы, как echo
echo :: a -> Mealy (Maybe a) a
echo a = Mealy go where
go Nothing = (a, echo a)
go (Just a') = (a', echo a')
которая позволяет вводить в switch
в внутреннее «состояние» Потока. Конечно, сейчас это нечто более мощное. Я назвал его машиной Мили, потому что он образует определенный (в) конечный автомат.
Что мало неочевидно, однако, что Mealy
образует Category
.
instance Category Mealy where
id = Mealy (\a -> (a, id))
Mealy bc . Mealy ab = Mealy $ \a -> case ab a of
(b, nab) -> case bc b of
(c, nbc) -> (c, nbc . nab)
В этом случае, мы объединяем две Mealy
машины, построив третью, который подает свои входы в первую машину, берет выходов первой машины на вторую машину, а затем возвращает окончательный вывод вместе с обновленным в составе пары ,
Если это интересно и вы не против изучать большой пакет с довольно разреженной документацией, тогда все это доступно в пакете machines
на Hackage.
В частности, каждая «стрелка» является категорией. В дикой природе есть много интересного «Стрелы». Я бы начал там. –
Вы также можете быть заинтересованы в [этой статье, которую я написал] (http://www.haskellforall.com/2012/08/the-category-design-pattern.html) на примерах категорий и там используется. –