2017-05-24 18 views
8

次typechecks:それは(代替f、Foldable f)=> Monad fですか?

instance (Applicative f, Alternative f, Foldable f) => Monad f where 
    (>>=) = flip $ \f -> foldr (<|>) empty . fmap f 
    -- Or equivalently 
    a >>= b = getAlt . foldMap Alt . fmap b $ a 

が、これは実際に有効なMonadインスタンスですか?はいの場合、それはなぜ使用されないのですか?もしそうでなければ、それはどんな法則を破るか?私は法律が成立していることを証明していませんが、反例も見つけられませんでした。

+2

*それは*どんな法則も破らないからではありません。モナドの自動導出を望んでいないのは、モナドを別の方法で実装することができるからです。 –

+0

たとえば、連想配列(辞書)をサポートする型クラスがある場合、それをある種の状態モナドとして定義することができます。しかし、おそらくあなたは状態モナドとしてではなく、(エミュレートされた)プロセッサとして機能する連想配列を必要とします。 –

答えて

7

これは正しいアイデンティティモナド法の反例であるべきです。

以下、GHC.Genericsのファンクタ製品Maybe :*: Maybeを利用していますが、必要に応じてインライン化することができます。これはまた、適用可能な、代替の、折りたたみ可能な、およびモナドでもある。私はこれらの事例の図書館が法を遵守していると信じています。

次に、提案されたinstance Monad(質問の1つ)を標準ライブラリ1と比較します。適切なアイデンティティー法は、提案されたインスタンスには満足していませんが、ライブラリインスタンスで(少なくとも私の限られたテストでは)保持されているように見えます。

{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, TypeOperators #-} 
{-# OPTIONS -Wall #-} 

module NotAMonad where 

import Control.Applicative 
import GHC.Generics ((:*:)(..)) 

-- A basic wrapper to avoid overlapping instances, and to be able to 
-- define a custom monad instance. 
newtype Wrap m a = Wrap { unWrap :: m a } 
    deriving (Functor, Applicative, Alternative, Foldable, Show) 

-- The proposed instance 
instance (Applicative f, Alternative f, Foldable f) => Monad (Wrap f) where 
    (>>=) = flip $ \f -> foldr (<|>) empty . fmap f 

-- This is Applicative, Alternative, and Foldable 
type T = Maybe :*: Maybe 

-- A basic test 
test :: Wrap T Int 
test = Wrap (Just 3 :*: Just 4) >>= return 
-- result: 
-- Wrap {unWrap = Just 3 :*: Just 3} 

4は今3に置き換えられます。私は理由を説明しようとしていない。 それはJust 3 <|> Just 4 = Just 3によって引き起こされると思います。

は、ライブラリのモナドのインスタンスを使用して、代わりに、すべてが正常に見える:

> (Just 3 :*: Just 4) >>= return 
Just 3 :*: Just 4 
5

Alternativeがハック獣のビットです。本質的にモノイドコンストラクタのクラス:タイプコンストラクタTです。これは、任意の包含タイプに対してX,T Xがモノイドです。これは実際にファンクターモナドとはあまり関係がなく、数学的にはかなり深刻です。 (だから、唯一の数学的な優雅さのために、AlternativeMonadを設定するビット悪いだろう。)

のは、(これは実際にはコンパイルされません)明確にするためMonoidの面でそのインスタンスを書いてみましょう:

instance (Foldable f, (∀ x . Monoid (f x))) => Monad f where 
    (>>=) = flip $ \f -> foldr mappend empty . fmap f 
     ≡ flip $ \f -> fold . fmap f 
     ≡ flip foldMap 

(=<<) = foldMap 

または実際にはそう、これは間違いなく、未知のものではありません。法律を確認するには

、我々Kleisli製剤で最高の表情:

(f <=< g) x = f =<< g x 
       ≡ foldMap f $ g x 

すなわち、

f <=< g = foldMap f . g 

そして、モナドの法則がある

  • 左アイデンティティ

    f <=< pure ≡ foldMap f . pure =! f 
    
  • 右アイデンティティ

    pure <=< f ≡ foldMap pure . f =! f 
    
  • 結合性

    (f <=< g) <=< h ≡ foldMap (foldMap f . g) . h 
           =! foldMap f . foldMap g . h 
           ≡ foldMap f . (foldMap g . h) ≡ f <=< (g <=< h) 
    

はそう簡単では、我々は、ff

  • foldMap (foldMap f . g) =! foldMap f . foldMap g∀確かに不合理ではないに見えますg
    • foldMap f . pure =! f =! foldMap pure . fを必要とするが、私は表示されませんあなたはいつでも厳密にそれを締結することができましたFoldable + Alternativeインスタンス。

      本当に、私がこのインスタンスで目にする大きな問題は、それほど一般的ではないということです。ほとんどのモナドはFoldableでもAlternativeでもありません。あなたが提案したようなカバー・オールの定義があった場合は、自分のインスタンスを定義するためにはOverlappingInstancesが必要になり、正当な理由なく使用しないでください。

      bindメソッドに対して次のデフォルトの定義で何か問題があるならば、私はしかし不思議です:

      {-# LANGUAGE DefaultSignatures #-} 
      class Applicative f => Monad f where 
          return :: a -> m a 
          return = pure 
          (>>=) :: m a -> (a -> m b) -> m b 
          default (>>=) :: (Foldable m, Monoid m b) 
            => m a -> (a -> m b) -> m b 
          (>>=) = flip foldMap 
      

      少なくとも例えば定義することが可能になりますfoldMap ≡ concatMap ≡ (=<<)、十分に確認してください以降のすべてのメソッドを書くために必要とせず、単に

      instance Monad [] 
      

      としてリストインスタンス。

    +0

    折りたたみ可能なモノイドが本質的にはisoまでのリストであるのだろうかと思います。私はデフォルトの定義で問題を見ることはできませんが、多分それは '[] 'にしか適用されず、少ししか(?) – chi

    +1

    @chiにしか当てはまらないかもしれません。自由なモノイドの定義について考えてみましょう。 'foldMap'はあなたに1ビットを与えますが、' foldMap f(singleton x)= f x'で 'singleton'も必要です。もちろんfoldMap f(x <> y)= foldMap f x <> foldMap f y'が必要です。もちろん、その時点で、あなたはfdreeに対してそうすることができるので、必ずTraversableで投げてください。 – dfeuer

    +0

    @chi 'Last'と' First'です。 –