多分、標準的な例はベクトルによって与えられます。
data Nat = Z | S Nat deriving (Show, Eq, Ord)
data Vec :: Nat -> * -> * where
V0 :: Vec Z x
(:>) :: x -> Vec n x -> Vec (S n) x
まず、シングルトンを定義してクラスにラップすることで、少しの努力でそれを適用することができます。
data Natty :: Nat -> * where
Zy :: Natty Z
Sy :: Natty n -> Natty (S n)
class NATTY (n :: Nat) where
natty :: Natty n
instance NATTY Z where
natty = Zy
instance NATTY n => NATTY (S n) where
natty = Sy natty
今度は私は(Traversable
インスタンスからfmapDefault
を介して抽出されるべきである)Functor
インスタンスを省略Applicative
構造
instance NATTY n => Applicative (Vec n) where
pure = vcopies natty
(<*>) = vapp
vcopies :: forall n x. Natty n -> x -> Vec n x
vcopies Zy x = V0
vcopies (Sy n) x = x :> vcopies n x
vapp :: forall n s t. Vec n (s -> t) -> Vec n s -> Vec n t
vapp V0 V0 = V0
vapp (f :> fs) (s :> ss) = f s :> vapp fs ss
を開発することができます。
今、Applicative
に対応するMonad
インスタンスがありますが、それは何ですか? 対角線思考!それが必要なのです!ベクトルは有限領域からの関数の表として見ることができるので、Applicative
はK-およびS-コンビネータの単なる表であり、Monad
はReader
のような振る舞いを持っています。
vtail :: forall n x. Vec (S n) x -> Vec n x
vtail (x :> xs) = xs
vjoin :: forall n x. Natty n -> Vec n (Vec n x) -> Vec n x
vjoin Zy _ = V0
vjoin (Sy n) ((x :> _) :> xxss) = x :> vjoin n (fmap vtail xxss)
instance NATTY n => Monad (Vec n) where
return = vcopies natty
xs >>= f = vjoin natty (fmap f xs)
あなたはより直接的>>=
を定義することによって、ビットを節約するかもしれませんが、あなたはそれをカットどのような方法は、モナド行動は非対角計算のための役に立たないサンクを作成します。怠惰は、アーケードドン要因によって減速するのを防ぐかもしれませんが、<*>
のジッパー動作は、少なくとも行列の対角を取るよりも少し安いことになります。
facebookで[The Haxl project](https://github.com/meiersi/HaskellerZ/blob/master/meetups/20130829-FPAfternoon_The_Haxl_Project_at_Facebook/The%20Haxl%20Project%20at%20Facebook.pdf?raw=true)でインタレースされました。計算を並列化することができるアプリケーションを使用します。モナドインターフェースを使用して計算を並列化することはできません。 – bennofs