サーチ…


前書き

Applicativeは、 f :: * -> *型のクラスであり、関数がその構造体にも埋め込まれている構造体に対して関数を持ち上げることができます。

備考

定義

class Functor f => Applicative f where
    pure  :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

fFunctor制約に注意してください。 pure関数は、 Applicative構造体に埋め込まれた引数を返します。中置関数<*> ( "apply"と発音)は、 Applicative構造体に埋め込まれた関数を除いて、 fmapと非常に似ていApplicative

Applicativeの正しいインスタンスは、コンパイラによって強制されませんが、 適用法を満たす必要があります

pure id <*> a = a                              -- identity
pure (.) <*> a <*> b <*> c = a <*> (b <*> c)   -- composition
pure f <*> pure a = pure (f a)                 -- homomorphism
a <*> pure b = pure ($ b) <*> a                -- interchange

別の定義

すべてのApplicative FunctorはFunctorであるため、常にfmapを使用することができます。したがってApplicativeの本質は、運ばれたコンテンツのペアリングとそれを作成する能力です。

class Functor f => PairingFunctor f where
  funit :: f ()                  -- create a context, carrying nothing of import
  fpair :: (f a,f b) -> f (a,b)  -- collapse a pair of contexts into a pair-carrying context

このクラスはApplicativeと同型です。

pure a = const a <$> funit = a <$ funit  

fa <*> fb = (\(a,b) -> a b) <$> fpair (fa, fb) = uncurry ($) <$> fpair (fa, fb)

逆に、

funit = pure ()

fpair (fa, fb) = (,) <$> fa <*> fb

Applicativeの共通インスタンス

多分

Maybe 、不在の価値を含んでいる応用ファンクタです。

instance Applicative Maybe where
    pure = Just
    
    Just f <*> Just x = Just $ f x
    _ <*> _ = Nothing

pureにそれにJust適用することによって、与えられた価値をMaybe持ち上げる。 (<*>)関数は、に包まれた関数を適用Maybeの値にMaybe 。関数と値の両方が存在する場合( Just構成されている場合)、その関数がその値に適用され、ラップされた結果が返されます。いずれかが見つからない場合、計算を続行できず、代わりにNothingが返されます。

リスト

リストがタイプシグネチャ<*> :: [a -> b] -> [a] -> [b]に適合する1つの方法は、2つのリストのデカルト積を取り、最初のリストの各要素をそれぞれ2番目の要素:

fs <*> xs = [f x | f <- fs, x <- xs]
         -- = do { f <- fs; x <- xs; return (f x) }

pure x = [x]

これは、通常、非決定主義をエミュレートするものとして解釈されます。したがって、2つの非決定論的値の組み合わせは、2つのリストの値のすべての可能な組み合わせに及ぶ。

ghci> [(+1),(+2)] <*> [3,30,300]
[4,31,301,5,32,302]

無限のストリームとジップリスト

2つの入力を一緒に "ジップ"するApplicativeのクラスがありApplicative 。単純な例の1つは、無限のストリームの例です。

data Stream a = Stream { headS :: a, tailS :: Stream a }

StreamApplicativeインスタンスは、引数のストリームに関数のストリームをポイントごとに適用し、2つのストリームの値を位置ごとにペアにします。 pureは一定のストリームを返す - 単一の固定値の無限リスト:

instance Applicative Stream where
    pure x = let s = Stream x s in s
    Stream f fs <*> Stream x xs = Stream (f x) (fs <*> xs)

リストにもあまりにも "zippy" Applicativeインスタンスがあります。これにはZipList newtypeが存在しZipList

newtype ZipList a = ZipList { getZipList :: [a] }

instance Applicative ZipList where
    ZipList xs <*> ZipList ys = ZipList $ zipWith ($) xs ys

zipは最短入力に従って結果をトリムするので、 Applicative法を満たすpure実装は無限リストを返すものです:

    pure a = ZipList (repeat a)   -- ZipList (fix (a:)) = ZipList [a,a,a,a,...

例えば:

ghci> getZipList $ ZipList [(+1),(+2)] <*> ZipList [3,30,300]
[4,32]

2つの可能性は、最初のケースでは1列( nx 1 )の行列に1行( 1 xm )の行列を掛けたものと同様に、 nxm行列を結果として);または第1の場合には1行および1列の行列を掛け合わせる(但し、合計はしない)。

関数

関数(->) rに特化すると、 pure<*>の型シグネチャはそれぞれKS組み合わせの型シグネチャと一致します。

pure :: a -> (r -> a)
<*> :: (r -> (a -> b)) -> (r -> a) -> (r -> b)

pureconstでなければならず、 <*>は一対の関数をとり、固定引数にそれぞれ適用して2つの結果を適用します。

instance Applicative ((->) r) where
    pure = const
    f <*> g = \x -> f x (g x)

関数はプロトタイプの "ジッピー"アプリケーションです。たとえば、無限のストリームは(->) Natと同型であるため、...

-- | Index into a stream
to :: Stream a -> (Nat -> a)
to (Stream x xs) Zero = x
to (Stream x xs) (Suc n) = to xs n

-- | List all the return values of the function in order
from :: (Nat -> a) -> Stream a
from f = from' Zero
    where from' n = Stream (f n) (from' (Suc n))

...ストリームを高次の方法で表現すると、敏感なApplicativeインスタンスが自動的に生成されます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow