18

これは一般的な質問であり、特定のコードに関連付けられているわけではありません。

T aのインスタンスを与えることができる型があるとしますMonad。すべてのモナドは and のApplicative代入pure = returnであり(<*>) = ap、すべてのアプリケーションはFunctorviafmap f x = pure f <*> xであるため、最初のインスタンスを定義してからMonad、自明に and のインスタンスを与える方Tがよいでしょうか?ApplicativeFunctor

ちょっと後ろ向きな感じです。プログラミングの代わりに数学をやっていたとしたら、最初にオブジェクトがファンクターであることを示し、それがモナドであることを示すまで制限を追加し続けると思います。Haskell は単に圏論に触発されたものであり、証明を構築するときに使用する手法は、有用なプログラムを作成するときに使用する手法ではないことは明らかですが、Haskell コミュニティから意見を求めたいと思います。Monad下から下に行った方がいいFunctorですか?または からFunctorまでMonad?

4

5 に答える 5

25

Functor私は、インスタンスを最初に書いて見る傾向があります。LANGUAGE DeriveFunctorプラグマを使用すると、data Foo a = Foo a deriving ( Functor )ほとんどの場合に機能するため、二重にそうです。

Applicative注意が必要なのは、あなたがあなたよりも一般的である場合のインスタンスの合意に関するものMonadです。たとえば、これはErrデータ型です

data Err e a = Err [e] | Ok a deriving ( Functor )

instance Applicative (Err e) where
  pure = Ok
  Err es <*> Err es' = Err (es ++ es')
  Err es <*> _       = Err es
  _      <*> Err es  = Err es
  Ok  f  <*> Ok  x   = Ok (f x)

instance Monad (Err e) where
  return = pure
  Err es >>= _ = Err es
  Ok  a  >>= f = f a

上記でインスタンスを順番に定義しましたが、Functor個別に見てみるMonadと、各インスタンスは正しいものです。残念ながら、ApplicativeMonadインスタンスは一致しません:apとは、とのように明らかに(<*>)異なります。(>>)(*>)

Err "hi" <*>  Err "bye" == Err "hibye"
Err "hi" `ap` Err "bye" == Err "hi"

感性のために、特に Applicative/Monad Proposal が全員の手に渡ると、これらは一致するはずです。定義した場合instance Applicative (Err e) where { pure = return; (<*>) = ap }、それら整列します。

Applicativeしかし、最終的には、との違いを慎重に分解してMonad、それらが無害な方法で異なる動作をするようにすることができるかもしれませんApplicative。これは実際にはかなり頻繁に発生しており、「無害」とは何を意味し、どのような種類の「観察」の下でインスタンスを調整する必要があるかについて、陪審はまだ少し外れていると感じています。おそらく、これが最も多く使用されているのは Facebook の Haxl プロジェクトです。このプロジェクトでは、Applicativeインスタンスがインスタンスよりも並列Monad化されているため、かなり重大な「観察されない」副作用を犠牲にしてはるかに効率的です。

いずれにせよ、それらが異なる場合は、それを文書化してください。

于 2013-10-28T13:03:01.577 に答える
6

私はしばしば、エイブラハムソンの答えとは逆のアプローチを選択します。Monadインスタンスのみを手動で定義し、 で既に定義されている関数を使用してApplicativeandを定義します。これにより、これらのインスタンスは絶対にどのモナドでも同じになります。つまり、次のようになります。FunctorControl.Monad

instance Applicative SomeMonad where
  pure = return
  (<*>) = ap

instance Functore SomeMonad where
  fmap = liftM

このようにFunctorandの定義Applicativeは常に「無脳」であり、非常に簡単に推論できますが、インスタンスをより効率的に実装したり、新しい機能を提供したりすることができる場合があるため、これが究極の解決策ではないことに注意する必要があります。 . たとえば、 のApplicativeインスタンスConcurrentlyは物事を同時に実行しますが、Monadインスタンスはネイチャー モナドのために順次しか実行できません。

于 2013-10-28T19:54:20.297 に答える
3

Functor通常、インスタンスは非常に簡単に定義できますが、通常は手動で定義します。

ApplicativeとについてMonadは、場合によります。pure通常は同様にreturn簡単で、拡張された定義をどのクラスに置くかは問題ではありません。バインドの場合、「カテゴリの方法」を使用することが有益な場合があります。つまり、join' :: (M (M x)) -> M x最初に特殊化されたものを定義してから定義します (もちろん、 に関してa>>=b = join' $ fmap b a定義した場合は機能しません)。次に、インスタンスを再利用するだけでおそらく便利です。fmap>>=(>>=)Applicative

それ以外の場合、Applicativeインスタンスは非常に簡単に記述できたり、一般的な Monad から派生した実装よりも効率的です。その場合は、必ず<*>個別に定義する必要があります。

于 2013-10-28T13:01:17.543 に答える
0

Haskell でサブクラスがどのように機能するかを誤解していると思います。オブジェクト指向のサブクラスとは違います! 代わりに、次のようなサブクラスの制約

class Applicative m => Monad m

「正規構造を持つ型は、正規Monad構造も持つ必要があります」と述べていApplicativeます。このような制約を設定する理由は、基本的に次の 2 つです。

  • サブクラス構造は、スーパークラス構造を誘導します。
  • スーパークラス構造は、サブクラス構造の自然なサブセットです。

たとえば、次のことを考慮してください。

class Vector v where
    (.^) :: Double -> v -> v
    (+^) :: v -> v -> v
    negateV :: v -> v

class Metric a where
    distance :: a -> a -> Double

class (Vector v, Metric v) => Norm v where
    norm :: v -> Double

最初のスーパークラスの制約がNorm発生するのは、ベクトル空間構造も想定しない限り、ノルム空間の概念が非常に弱いためです。2 つ目は、(ベクトル空間が与えられた場合) aが aNormを誘導するためMetricに発生します。これは、次のことを観察することで証明できます。

instance Metric V where
    distance v0 v1 = norm (v0 .^ negateV v1)

有効なインスタンスと有効な関数を持つanyの有効なMetricインスタンスです。ノルムがメトリックを誘導すると言います。http://en.wikipedia.org/wiki/Normed_vector_space#Topological_structureを参照してください。 VVectornorm

FunctorApplicativeスーパークラスMonadは のようMetricであり、 のようではありませんVector:インデュースと構造のreturn>>=関数:MonadFunctorApplicative

  • fmap:は Haskell 98 標準ライブラリにfmap f a = a >>= return . fあったとして定義できます。liftM
  • purereturn: ;と同じ操作です。2 つの名前は、Applicativeが のスーパークラスではなかったときの遺産ですMonad
  • <*>:は Haskell 98 標準ライブラリにaf <*> ax = af >>= \ f -> ax >>= \ x -> return (f x)あったとして定義できます。liftM2 ($)
  • join: として定義できますjoin aa = aa >>= id

Functorしたがって、とのApplicative操作を の観点から定義することは、数学的に完全に賢明ですMonad

于 2015-04-15T16:30:11.327 に答える