12

この質問は、モナドである何かから適切なインスタンスを構築することを扱いMonadますが、特定の制約の下でのみ - たとえばSet. トリックは、それを にラップすることContTです。これにより、制約がその値のラップ/ラップ解除に延期されます。

今、私はsで同じことをしたいと思いますApplicative。特に、pureに型クラスの制約があるApplicativeインスタンスがあります。有効なインスタンスを構築する方法と同様のトリックはありますか?Applicative

(モナドの場合と同じように、「すべてのアプリケーション ファンクターの母」は存在しますか?)

4

3 に答える 3

5

利用可能な最も一貫性のある方法はCategory、 から開始することです。ここでは、オブジェクトに制限があるのは非常に自然です: Object !

class Category k where
  type Object k :: * -> Constraint
  id :: Object k a => k a a
  (.) :: (Object k a, Object k b, Object k c)
     => k b c -> k a b -> k a c

次に、Edwardと同じようにファンクターを定義します。

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

これらはすべてうまく機能し、constrained-categories ライブラリに実装されています。– まだ Hackage にはありません。

Applicative残念ながら、実行するのは少し簡単ではありません。数学的には、これらはモノイド関手であるため、最初に モノイド圏が必要です。categoriesにはそのクラスがありますが、オブジェクトは常に制約のある種類のものであるため、制約ベースのバージョンでは機能しません*。だから私がしたことは、Curryクラスを構成することです。これは、これに近似したものです。

Monoidal次に、ファンクターを実行できます。

class (Functor f r t, Curry r, Curry t) => Monoidal f r t where
  pure :: (Object r a, Object t (f a)) => a `t` f a
  fzipWith :: (PairObject r a b, Object r c, PairObject t (f a) (f b), Object t (f c))
              => r (a, b) c -> t (f a, f b) (f c)

これは実際にApplicativeは、適切な閉じたデカルト カテゴリがある場合と同じです。制約付きカテゴリのバージョンでは、残念ながら署名は非常にひどいものに見えます。

  (<*>) :: ( Applicative f r t
           , MorphObject r a b, Object r (r a b)
           , MorphObject t (f a) (f b), Object t (t (f a) (f b)), Object t (f (r a b))
           , PairObject r (r a b) a, PairObject t (f (r a b)) (f a)
           , Object r a, Object r b, Object t (f a), Object t (f b))
       => f (r a b) `t` t (f a) (f b)

それでも、それは実際には機能します。重要な制約でそれを使用する便利な方法をまだ見つけていません。

ただし、Applicativeは と同等でありMonoidalで示すように使用できます。Set

于 2014-01-15T00:51:23.160 に答える
4

異なるプレゼンテーションは同形ではないため、「制限付きアプリケーション」の概念が一意であるかどうかはわかりません。ここで述べたのは、Codensity の線に少なくともいくらか沿ったものです。アイデアは、ユニットと一緒に「フリーファンクター」を持つことです

{-# LANGUAGE TypeFamilies, ConstraintKinds, ExistentialQuantification #-}

import GHC.Prim (Constraint)
import Control.Applicative

class RFunctor f where
  type C f :: * -> Constraint
  rfmap :: C f b => (a -> b) -> f a -> f b

class RFunctor f => RApplicative f where
  rpure :: C f a => a -> f a
  rzip :: f a -> f b -> f (a,b)

data UAp f a
  = Pure  a
  | forall b. Embed (f b) (b -> a)

toUAp :: C f a => f a -> UAp f a
toUAp x = Embed x id

fromUAp :: (RApplicative f, C f a) => UAp f a -> f a
fromUAp (Pure x) = rpure x
fromUAp (Embed x f) = rfmap f x

zipUAp :: RApplicative f => UAp f a -> UAp f b -> UAp f (a,b)
zipUAp (Pure a) (Pure b) = Pure (a,b)
zipUAp (Pure a) (Embed b f) = Embed b (\x -> (a,f x))
zipUAp (Embed a f) (Pure b) = Embed a (\x -> (f x,b))
zipUAp (Embed a f) (Embed b g) = Embed (rzip a b) (\(x,y) -> (f x,g y))

instance Functor (UAp f) where
  fmap f (Pure a) = Pure (f a)
  fmap f (Embed a g) = Embed a (f . g)

instance RApplicative f => Applicative (UAp f) where
  pure = Pure
  af <*> ax = fmap (\(f,x) -> f x) $ zipUAp af ax

編集: いくつかのバグを修正しました。それは、投稿する前にコンパイルしないとどうなるかです。

于 2014-01-13T21:13:09.823 に答える
0

すべての Monad は Functor であるため、同じ ContT トリックを使用できます。

pureになるreturn

fmap f xになるx >>= (return . f)

于 2014-01-13T21:02:35.837 に答える