Functor
andのような抽象化を使用することでコードが恩恵を受ける状況に遭遇しましたApplicative
が、種類は(* -> *) -> *
. 高カインド ファンクターの定義は、次のRankNTypes
ように行うことができます
class HFunctor f where
hfmap :: (forall x. a x -> b x) -> f a -> f b
しかし、より高い種類の のバージョンはApplicative
少しトリッキーです。これは私が思いつくことができる最高のものです:
class HFunctor f => HApplicative f where
hpure :: (forall x. a x) -> f a
(<**>) :: f (a :-> b) -> f a -> f b
newtype (:->) a b x = HFunc (a x -> b x)
infixr 5 :->
:->
kind の関数を持つにはラッパー型が必要ですが、これでは、通常の Applicative の場合の* -> *
ように、関数アプリケーションを適切に連鎖させることはできません。などのヘルパーで管理できます<$>
<*>
liftHA2 :: HApplicative f => (forall x. a x -> b x -> c x) -> f a -> f b -> f c
liftHA2 f fa fb = hpure (fun2 f) <**> fa <**> fb where
fun2 = HFunc . (HFunc .)
しかし、任意のアリティの関数を「持ち上げる」ための一般的な方法があると便利です。
上記のインスタンスを使用する簡単な例:
data Example f = Example (f Int) (f String)
instance HFunctor Example where
hfmap f (Example i s) = Example (f i) (f s)
instance HApplicative Example where
hpure a = Example a a
Example (HFunc fi) (HFunc fs) <**> Example i s = Example (fi i) (fs s)
e :: Example []
e = Example [1,2,3] ["foo", "bar"]
e' :: Example ((,) Int)
e' = hfmap (length &&& head) e -- Example (3,1) (2, "foo")
e'' :: Example []
e'' = liftHA2 (++) e e -- Example [1,2,3,1,2,3] ["foo", "bar", "foo", "bar"]
だから、私の質問は:上記の型クラスは何と呼ばれ、それらはハックのいくつかのライブラリによってすでに提供されていますか? Functor2
グーグルで私はinlinear-maps
とHFunctor
inを思いつきましたmulti-rec
が、どちらも私が必要としているものを正確にはしません。
HApplicative
また、ラッパーなしで書く方法:->
や、関数のリフティングを容易にする他の方法はありますか?