利用可能な最も一貫性のある方法は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