Чисто синтаксическая разница, заключающаяся в том, что, несмотря на то, что является поверхностным, на самом деле может быть наиболее распространенным вариантом использования, заключается в том, что <<<
имеет более низкий приоритет, чем .
:
infixr 9 Control.Category..
infixr 1 Control.Category.<<<
Это похоже на разницу между простым приложением функции f x
(которое связывается более жестко, чем любой инфикс, так что это в основном infixl 10
) и использованием оператора $
, например f $ x
, который имеет самый низкий приоритет infixr 0 $
. Это означает, что вы можете выбрать, для какого из них требуется меньше скобок в выражении. <<<
удобно, когда вы хотите составить функции, которые сами определены неким выражением инфикса; это часто случается при работе с объективами .
Теоретически интереснее то, что версия Category
работает не только с функциями, но и с морфизмами из других скважин, категорий . Простым примером является категория принуждений : если у вас есть, например, список newtype
-обернутых значений, и вы хотите получить базовые представления, было бы неэффективно map
по списку - это создаст копию всего списка, который, однако, содержит точно такую же информацию времени выполнения. Принуждение позволяет вам использовать исходный список все время, но без обхода системы типов - в каждой точке компилятор будет отслеживать, в каком «представлении» списка элементы имеют какой тип. Принуждения на самом деле не являются функциями - они всегда запрещены во время выполнения - но они могут быть скомпонованы точно так же, как функции (например, принуждение от Product Int
до Int
, затем приведение к Int
до Sum Int
).
Для других примеров Haskellers обычно ссылаются на категории Kleisli
. Они содержат функции вида a -> m b
, где m
- монада. Хотя вы не можете напрямую сочинять, например, readFile :: FilePath -> IO String
с firstFileInDirectory :: FilePath -> IO FilePath
, поскольку существует несоответствие между FilePath
и IO FilePath
, вы можете Kleisli составить их:
import Control.Monad
main = writeFile "firstfileContents.txt" <=< readFile <=< firstFileInDirectory
$ "src-directory/"
и тоже самое можно написать
import Control.Arrow
main = runKleisli ( Kleisli (writeFile "firstfileContents.txt")
<<< Kleisli readFile
<<< Kleisli firstFileInDirectory
) $ "src-directory/"
Какой смысл ? Ну, это позволяет вам абстрагироваться от различных категорий и, таким образом, иметь код, который будет работать как с чистыми функциями, так и с IO
функциями. Но, честно говоря, я думаю, что Kleisli
плохо справляется с мотивацией использования других категорий: все, что вы можете написать с помощью стрелок Клейсли, обычно более читабельно при написании со стандартной монадической нотацией do
, или же просто с =<<
или <=<
операторов. Это все же позволяет вам абстрагироваться от вычислений, которые могут быть чистыми или нечистыми, просто выбирая разные монады (IO
, ST
или просто Identity
).
По-видимому, есть некоторые специализированные парсеры, которые Arrows
, но не могут быть записаны как монады, но они на самом деле не завоевали популярность - кажется, преимущества не уравновешивают менее интуитивный стиль.
В математике есть много более интересных категорий, но, к сожалению, они, как правило, не могут быть выражены как Category
es, потому что не каждый тип Haskell может быть объектом . Пример, который я хотел бы привести, - это категория линейных отображений , объектами которой являются только типы Haskell, представляющие векторные пространства, такие как Double
или (Double, Double)
или InfiniteSequence Double
. Линейные отображения по существу являются матрицами, но имеют не только проверенную типоразмерность доменов и кодоменов, но и возможность представлять различные пространства с особым значением, например, предотвращение добавления вектора положения к вектору гравитационного поля. А поскольку векторы не обязательно должны быть буквально представлены массивами чисел, вы можете иметь оптимизированные представления для каждого приложения, например, для сжатых данных изображения, на котором вы хотите сделать машинное обучение.
Линейные отображения не являются экземпляром Category
, но они являются экземпляром ограниченной категории .