Как насчет стрел?
Просматривая различные обучающие материалы о различных классах тематических классов Haskell, мы находим такие вещи, как Monoid
, Functor
, Monad
и т.д. - все из которых имеют десятки экземпляров. Но по какой-то причине, когда мы достигаем Arrow
, есть только два экземпляра: функции и монады. В обоих случаях использование экземпляра Arrow
менее сильное и сложнее, чем просто непосредственное использование основной вещи.
Есть ли у кого-нибудь интересные примеры стрелок? Я уверен, что должно быть что-то, но я никогда не сталкивался с ними ни о чем писать...
Ответы
Ответ 1
HXT, библиотека, которая используется для синтаксического анализа XML, является очень хорошим примером использования стрелок (посмотрите, как часто слово Arrow
происходит в именах модулей этого пакета!). Вы должны посмотреть на большой учебник: http://adit.io/posts/2012-04-14-working_with_HTML_in_haskell.html
Но также хорошо иметь концепцию стрелки для функций. Например, следующий код
((+1) &&& (*2)) 3 -- result is (4,6)
просто работает, потому что (->)
является экземпляром класса стрелок (оператор &&&
определяется в Control.Arrow).
Благодаря синтаксису arrow у вас также есть отличный инструмент для написания сложных вычислений в Haskell (он также работает для функций, монад и фильтров XML в HXT).
Ответ 2
Мне нравится думать о Arrow
как оправляемых ациклических графах. Например, стрелка типа:
SomeArrow (a, b, c) (d, e, f)
... вы можете представить в виде графика, который имеет три входящих края типа a
, b
и c
и три исходящих ребра типа d
, e
и f
.
Используя эту интерпретацию, операции композиции категории для Arrow
похожи на горизонтальную конкатенацию для графов, соединяющих их ребра вместе:
(.) :: SomeArrow b c -> SomeArrow a b -> Some Arrow a c
... где a
, b
и c
могут быть самими кортежами. Аналогично, id
- это только тождественный граф, который пересылает все входящие ребра к исходящим ребрам:
id :: SomeArrow a a
Другая операция ключа - (***)
, которая похожа на вертикальную конкатенацию графиков:
(***) :: Arrow a b -> Arrow c d -> Arrow (a, c) (b, d)
Вы можете думать об этом как о поведении двух графиков бок о бок, объединяя их входные ребра и выходные ребра.
So Arrow
обычно возникает при работе с типизированными направленными ациклическими графами. Однако причина, по которой вы обычно не видите их часто, заключается в том, что большинство людей мысленно связывают графики с нетипизированными и высокопроизводительными структурами данных.