Примеры декартовых (профюнктор)? - PullRequest
0 голосов
/ 14 декабря 2018

Я просматриваю следующий пример кода и мне было трудно понять, как использовать (->) и (Star f) после того, как они реализовали 'first' и стали участником Cartisian.

МожетКто-нибудь предоставляет несколько простых для понимания примеров для тех?Спасибо.

-- Intuitively a profunctor is cartesian if it can pass around additional
-- context in the form of a pair.

class Profunctor p => Cartesian p where
  first  :: p a b -> p (a, c) (b, c)
  first = dimap swapP swapP . second

  second :: p a b -> p (c, a) (c, b)
  second = dimap swapP swapP . first

instance Cartesian (->) where
  first :: (a -> b) -> (a, c) -> (b, c)
  first f = f `cross` id

instance Functor f => Cartesian (Star f) where
  first :: Star f a b -> Star f (a, c) (b, c)
  first (Star f) = Star $ (\(fx, y) -> (, y) <$> fx) . (f `cross` id)

1 Ответ

0 голосов
/ 14 декабря 2018

Внимание, впереди мнения!

Профукторы - это немного чрезмерная абстракция.ИМО, мы должны в первую очередь говорить о категориях ;на практике большинство профессоров являются категориями, а не наоборот.Класс profunctor может иметь правильное применение, но на самом деле он гораздо более ограничен и привязан к категории Hask .Я предпочитаю делать это явным, говоря о категориях, конструкторы стрелок которых Hask -функторы в последнем аргументе и контравариантные Hask -функторы в аргументе pænultimate.Да, это глоток, но в этом суть: на самом деле это довольно специфическая ситуация, и часто оказывается, что вам действительно нужна только менее конкретная категория.
Конкретно, Cartesian более естественно рассматривается как класс категорий.не профункторы:

class Category k => Cartesian k where
  swap :: k (a,b) (b,a)
  (***) :: k a b -> k a' b' -> k (a,a') (b,b')

Что позволяет

first :: Cartesian k => k a b -> k (a,c) (b,c)
first f = f *** id
second :: Cartesian k => k a b -> k (c,a) (c,b)
second f = id *** f

, то есть категория-независимость id.(Вы также можете определить *** и second в терминах first, с second f=swap.first f.swap и f***g=first f.second g, но это неоправданно запутано IMO.)

Чтобы понять, почему я предпочитаю идти по этому пути,а не с профессорами, я хотел бы привести простой пример: , а не - профунктор: линейные отображения.

newtype LinearMap v w = LinearMap {
  runLinearMap :: v->w  -- must be linear, i.e. if v and w are finite-dimensional
                        -- vector spaces, the function can be written as matrix application.
 }

Это не профюнктор: хотя вымог бы с этой конкретной реализацией написать dimag f g (LinearMap a) = LinearMap $ dimap f g a, это не сохранит линейность.Это, однако, декартова категория:

instance Category LinearMap where
  id = LinearMap id
  LinearMap f . LinearMap g = LinearMap $ f . g
instance Cartesian LinearMap where
  swap = LinearMap swap
  LinearMap f *** LinearMap g = LinearMap $ f *** g

Хорошо, это выглядит довольно тривиально.Почему это интересно?Ну, линейные отображения могут быть эффективно сохранены в виде матриц, но концептуально они в первую очередь функции .Таким образом, имеет смысл обращаться с ними аналогично функциям;в этом случае . эффективно реализует умножение матриц, а *** собирает блочную диагональную матрицу , все в безопасном для типов виде.

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

Star - то, где это становится действительно интересным.

newtype Star f d c = Star{runStar :: d->f c}
instance Monad f => Category (Star f) where
  id = Star pure
  Star f . Star g = Star $ \x -> f =<< g x
instance Monad f => Cartesian (Star f) where
  swap = Star $ pure . swap
  Star f *** Star g = Star $ \(a,b) -> liftA2 (,) (f a) (g b)

Star является предшественником категории kleisli , которая, как вы, возможно, слышали, является одним из способов использования цепочек монадических вычислений.Итак, давайте перейдем прямо к IO примеру:

readFile' :: Star IO FilePath String
readFile' = Star readFile

writeFile' :: Star IO (FilePath,String) ()
writeFile' = Star $ uncurry writeFile

Теперь я могу сделать что-то вроде

copyTo :: Star IO (FilePath, FilePath) ()
copyTo = writeFile' . second readFile'

Зачем мне делать это таким образом?Дело в том, что я связал воедино действия ввода-вывода без использования интерфейса, который каким-либо образом может просматривать / изменять данные , которые передаются.Это может быть интересно для приложений безопасности.(Я только что составил этот пример; я уверен, что можно найти менее надуманные.)

В любом случае, я до сих пор не ответил на этот вопрос, потому что вы спрашиваете не о декартовых категориях, а о сильных профессора .Тем не менее, они предлагают почти одинаковый интерфейс:

class Profunctor p => Strong p where
  first' :: p a b -> p (a, c) (b, c)
  second' :: p a b -> p (c, a) (c, b)

, и, таким образом, я мог бы также внести незначительное изменение

copyTo :: Star IO (FilePath, FilePath) ()
copyTo = writeFile' . second' readFile'

, чтобы сохранить по существу тот же пример, но с Strong вместоCartesian.Я все еще использую композицию Category.И я считаю, что мы не сможем создать очень сложные примеры без какой-либо композиции.

Возникает большой вопрос: почему будет использовать интерфейс profunctor вместо категориального?Каковы проблемы, которые должны быть выполнены без композиции?Ответ лежит в значительной степени в Category экземпляре Star: там я должен был выполнить жесткое требование Monad f.Это не обязательно для экземпляров profunctor: они нужны только Functor f.Так что для наиболее сфокусированных примеров Star как сильного профессора вам нужно взглянуть на базовые функторы, которые являются , а не аппликативами / монадами.Важные области применения таких функторов в линзах Ван Лаарховена , и их внутренняя реализация действительно, вероятно, является наиболее проницательным примером для сильных профессоров.У меня постоянно кружится голова, когда я просматриваю источник библиотеки линз, но я думаю, что один весьма впечатляющий случай - Сильный индексированный .

...