2016-12-30 10 views
3

HackageでApplicative Functorsに言及されているように、それらは強力な緩やかな単相ファンクタです。なぜHaskellではその定義はそうのようにそれを表示されません:(starAp)monoidalファンクタとしての適用ファンクタ

class Functor f => MonoidalApplicative f where 
    mult :: f a -> f b -> f (a,b) 
    unit :: a -> f a 

    starAp :: f (a -> b) -> f a -> f b 
    starAp h x = fmap (uncurry ($)) (mult h x) 

<*>簡単乗算の観点から再構築し、この定義は私には単純に見えています。

それはあなたの答えにコメントで述べたように
instance MonoidalApplicative Maybe where 
    mult (Just x) (Just y) = Just (x,y) 
    mult _ _ = Nothing 

    unit x = Just x 
+6

'(<*>)'プレゼンテーションは、「マルチ」言語が実際にはいくつかの面でより淡いものであっても、日々のプログラミングにおいてより便利になる傾向があります(例:適用法は、このシナリオは '(>> =)'と 'join 'の間の関係に似ています。関連するブログ記事:http://blog.ezyang.com/2012/08/applicative-functors/ – duplode

+4

注:モノイド表示は、通常、 'unit :: f()'を持ちます。 'pure'は' pure x = fmap(const x)unit'で復元できます。 – duplode

+2

参照http://stackoverflow.com/a/27262462/414413 – Cirdec

答えて

4

join>>=と似たような話があります:exempleについては、こちらを多分インスタンスです。何かを定義する意味的に等価な方法がいくつかあるときは、常に最も効率的な方法を選択する方が良いです&実用的な方法。 Haskellはコードを書くように設計されていますが、何かを証明するためではありません(何とかHaskellはまだ残念ながら非常に普及したプログラミング言語にはなっていません)。

starApにデフォルト実装が実装されていると、ほとんど誰もそれを実装しません(Monadタイプクラスの>>と同じように)。しかし、<*>は非常に便利な操作です。それは多くの(megaparsecattoparsecoptparse-applicative)applicate &モナドパーサーで使用されており、私の人生を想像することはできませんliftA*に参加しています。そして、この操作ができるだけ効率的であることは非常に重要です。 starApfmap (uncurry ($)) (mult h x)として実装すると、コンパイラのインライン化や最適化が困難になることがあります。

また、multおよびunit操作を使用してApplicativeを表現しても実際には問題は解決されません。明らかに、mult = liftA2 (,)。しかし

mult (Just x) (Just y) = Just (x,y)

ない、完全に正しいと実装。実装が怠惰ではないためです。 1つだけ評価するのに十分な場合は、両方のケースを評価します。だから、あなたはまだこの単純な機能でさえ犯すことができます。したがって、この表現は厳密に悪い。

+0

しかしMonadの場合、実際にはAMPでMonadに 'join 'が追加されるはずです。それは技術的な困難のためではありませんでした:http://stackoverflow.com/questions/31552064/why-isnt-join-part-of-the-monad-class/31552223 – jpath

+0

それは単にパフォーマンス上の懸念ですか?それで、 'mult'と' <*> 'の両方をApplicativeに宣言して、それぞれがもう一方を呼び出すようにして、インスタンスがどちらをオーバーライドするか(あるいはその両方)を選択できるのはなぜですか?また、私が '<*>'に見たほとんどすべての呼び出しは完全に評価され、関数に変数があるものと同じ数だけ与えられます。たとえば、3変数関数の場合、私は 'liftA3 f x y z'を' f <$> x <*> y <*>z'にすることをお勧めします。そして、パフォーマンスの期待値は '<*>'ではなく 'liftA3'です。 –

+1

'liftA3 f x y z = f <$> x <*> y <*>z'の場合、この関数は' <*> 'より高速ではありません。そして、それは簡単に何かを完全に評価することはできません。例:2つの多分の和。 liftA2(+)(Just 3)(Just $ 2 ^(2^100)) 'があなたのマシンを殺している間、' liftA2(+)Nothing(Just $ 2 ^(2^100)) 'は即座に評価されます。非常に合法的なケース。 'mult = liftA2(、)'とそのような実装が十分に怠惰であるときに両方を定義するのはなぜですか? 1つの型クラスの中に複数の関数を許すのは、エラーを起こしやすいアプローチです。別の説明がここにあります:https://ghc.haskell.org/trac/ghc/wiki/Proposal/MonadOfNoReturn – Shersh

関連する問題