liftMはliftAと異なることがありますか?
-
06-07-2019 - |
質問
Typeclassopedia (他の情報源も含む)によると、 Applicative
は、論理的にはタイプクラス階層のMonad
とPointed
(したがってFunctor
)の間に属するため、Haskellプレリュードが今日書かれている場合、理想的には次のようになります。
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Pointed f where
pure :: a -> f a
class Pointed f => Applicative f where
(<*>) :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
-- either the traditional bind operation
(>>=) :: (m a) -> (a -> m b) -> m b
-- or the join operation, which together with fmap is enough
join :: m (m a) -> m a
-- or both with mutual default definitions
f >>= x = join ((fmap f) x)
join x = x >>= id
-- with return replaced by the inherited pure
-- ignoring fail for the purposes of discussion
(これらのデフォルト定義が Wikipediaの説明から私によって再入力された場所、エラーは私自身のものですが、エラーがある場合は少なくとも原則的には可能です。)
ライブラリは現在定義されているため、次のものがあります。
liftA :: (Applicative f) => (a -> b) -> f a -> f b
liftM :: (Monad m) => (a -> b) -> m a -> m b
and:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
ap :: (Monad m) => m (a -> b) -> m a -> m b
各ペア内のこれらのタイプの類似性に注意してください。
私の質問は:liftM
(liftA
とは異なる)およびap
(<*>
とは異なる)、<=>は<=>で設計されていないという歴史的現実の結果です>および<=>を念頭に置いていますか?それとも、<=>コンテキストのみを必要とするバージョンとは異なる、他のいくつかの動作方法(場合によっては、いくつかの正当な<=>定義)ですか?
異なる場合、Typeclassopediaなどで説明されているが強制されていない<=>、<=>、<=>、<=>の定義に必要な法則に従って、簡単な定義のセットを提供してもらえますかtype system)<=>と<=>の動作が異なりますか?
また、それらが明確でない場合、前提と同じ法律を使用してそれらの同等性を証明できますか?
解決
liftA
、liftM
、fmap
、および.
はすべて同じ関数である必要があり、ファンクターの法則を満たしている必要があります :
fmap id = id
ただし、これはHaskellによってチェックされません。
現在はApplicativeです。型と法則を満たす複数の実装が存在する可能性があるため、ap
と<*>
が一部のファンクターで異なる場合があります。たとえば、Listには複数の可能なApplicative
インスタンスがあります。次のようにアプリカティブを宣言できます。
instance Applicative [] where
(f:fs) <*> (x:xs) = f x : fs <*> xs
_ <*> _ = []
pure = repeat
liftM2 id
関数は引き続きMonad
として定義されます。これは、すべての[]
で無料で提供されるnewtype ZipList a = ZipList [a]
インスタンスです。しかし、ここでは、複数のZipList
インスタンスを持つ型コンストラクターの例がありますが、どちらも法を満たします。しかし、もしあなたのモナドと適用可能なファンクターが同意しないなら、それらのために異なるタイプを持つのは良い形と考えられます。たとえば、上記の<=>インスタンスは<=>のモナドと一致しないので、実際に<=>と言ってから<=>ではなく<=>の新しいインスタンスを作成する必要があります。
他のヒント
これらは 異なる場合がありますが、すべきではありません。
それらは異なる実装を持つことができるため異なる場合があります。1つはinstance Applicative
で定義され、もう1つはinstance Monad
で定義されます。しかし、実際にそれらが異なる場合、それらのインスタンスを書いたプログラマーは誤解を招くコードを書いたと思います。
あなたの言うとおりです。機能は歴史的な理由から存在しています。人々は物事がどうあるべきかについて強力なアイデアを持っています。