отображение стрелок над монадами

Я понимаю, что стрелка — это профунктор, в котором можно преобразовывать входные и выходные данные, но можно ли сопоставить стрелку поверх функтора?

Я понимаю, что в ответ на вопрос "нет", поскольку сигнатура типа функции fmap имеет значение (a -> b) -> f a -> f b и не допускает Arrow a b, но я надеюсь, что то, о чем я спрашиваю, понятно.

Я ищу способ, например, преобразовать ввод Maybe с помощью стрелки, где Nothing переходит к Nothing, а Just x переходит к Just y, где y является результатом применения стрелки к x.


person Matthew Piziak    schedule 15.04.2017    source источник


Ответы (2)


Arrow объединяет два понятия. Один из них, как вы говорите, принадлежит профунктору, но прежде всего это просто определенный класс категорий (о чем и свидетельствует суперкласс).

Это очень важно для этого вопроса: да, сигнатура fmap — это (a -> b) -> f a -> f b, но на самом деле это далеко не все, что может делать функтор! В математике функтор — это сопоставление двух категорий C и D, которое сопоставляет каждой стрелке в C стрелку в D. . Стрелки в разных категориях, то есть! Стандартный класс Functor просто охватывает простейший частный случай — эндофункторов в категории Hask.

Полная общая версия класса функтора на самом деле выглядит примерно так (здесь моя версия из ограниченных категорий):

class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
  fmap :: r a b -> t (f a) (f b)

Или, в псевдосинтаксисе,

class (Category (──>), Category (~>)) => Functor f (──>) (~>) where
  fmap :: (a ──> b) -> f a ~> f b

Это также может работать, когда одна из категорий является правильной стрелкой, а не обычной функциональной категорией. Например, вы можете определить

instance Functor Maybe (Kleisli [] (->)) (Kleisli [] (->)) where
  fmap (Kleisli f) = Kleisli mf
   where mf Nothing = [Nothing]
         mf (Just a) = Just <$> f a

использоваться как

> runKleisli (fmap . Kleisli $ \i -> [0..i]) $ Nothing
[Nothing]
> runKleisli (fmap . Kleisli $ \i -> [0..i]) $ Just 4
[Just 0,Just 1,Just 2,Just 3,Just 4]

Не уверен, будет ли это полезно для чего-то нетривиального, если использовать стандартные профункторные стрелки. Это определенно полезно в других категориях, которые не Hask-профункторы, например

instance (TensorSpace v) => Functor (Tensor s v) (LinearFunction s) (LinearFunction s)

выражая, что вы можете отобразить линейную функцию по одному фактору тензорного произведения (тогда как обычно невозможно отобразить нелинейную функцию по такому продукту - результат будет зависеть от выбора базиса в векторном пространстве).

person leftaroundabout    schedule 15.04.2017

Я ищу способ, например, преобразовать ввод Maybe со стрелкой, где Nothing переходит к Nothing, а Just x переходит к Just y, где y является результатом применения стрелки к x.

Это может быть реализовано для конкретных Functor (например, Maybe), хотя ArrowChoice, скорее всего, будет необходимо:

maybeAmap :: ArrowChoice p => p a b -> p (Maybe a) (Maybe b)
maybeAmap p =
    maybe (Left ()) Right
    ^>> returnA +++ p
    >>^ const Nothing ||| Just

См. Стрелочный эквивалент mapM? для аналогичной функции, написанной в proc-нотации.

Говоря о mapM, профункторы имеют интересный класс под названием Traversing:

-- Abbreviated class definition:
class (Choice p, Strong p) => Traversing p where
  traverse' :: Traversable f => p a b -> p (f a) (f b)
  wander :: (forall f. Applicative f => (a -> f b) -> s -> f t) -> p a b -> p s t

Флагманский экземпляр Traversing — это экземпляр для Starпрофунктор, который обеспечивает альтернативное кодирование знакомой функции traverse. Обратите внимание, что хотя leftaroundabout answer демонстрирует функтор не-Hask для категорий, которые не обязательно < strong>Hask-профункторы, с Traversing у нас есть конструкция для Profunctor, которые не обязательно имеют экземпляр Category.

person duplode    schedule 16.04.2017