2013-08-17 19 views
5

ひどいタイトルに申し訳ありません。私はタイプをラップするMonadApplicativeのインスタンスを作成しようとしています。(Monad m、Monoid o)=> m o?

instance (Monad m, Monoid o) => Applicative (m o) where 
    pure x = return mempty 
    xm <*> ym = do 
     x <- xm 
     y <- ym 
     return $ x `mappend` y 

これは機能しません。 GCHiは文句を言う:

Kind mis-match 
The first argument of `Applicative' should have kind `* -> *', 
but `m o' has kind `*' 
In the instance declaration for `Applicative (m o)' 

私が上に書いたことは意味をなさないかもしれないことを理解する。コンテキストは次のとおりです。私は、composという抽象化を、A pattern for almost compositional functionsの論文に記載されているように使用しようとしています。このツリー撮影(composのGADTのバージョンを使用して、私はそれをたくさん簡略化されました):

data Tree :: * -> * where 
    Var :: String -> Expr 
    Abs :: [String] -> Expr -> Expr 
    App :: Expr -> [Expr] -> Expr 

class Compos t where 
    compos :: Applicative f => (forall a. t a -> f (t a)) -> t c -> f (t c) 

instance Compos Tree where 
    compos f t = 
     case t of 
      Abs ps e -> pure Abs <*> pure ps <*> f e 
      App e es -> pure App <*> f e <*> traverse f es 
      _ -> pure t 

私は木を下降機能の多くを書くと言うエラーやのリストを返すつもりですなど、それは(そのような結合環境など)ダウンしたとしても、状態を必要としながら、文字列の集合、:

composFoldM :: (Compos t, Monad m, Monoid o) => (forall a. t a -> m o) -> t c -> m o 
composFoldM f = ??? 

checkNames :: (Tree a) -> State (Set Name) [Error] 
checkNames e = 
    case e of 
     Var n -> do 
      env <- get 
      -- check that n is in the current environment 
      return $ if Set.member n env then [] else [NameError n] 
     Abs ps e' -> do 
      env <- get 
      -- add the abstractions to the current environment 
      put $ insertManySet ps env 
      checkNames e' 
     _ -> composFoldM checkNames e 

data Error = NameError Name 
insertManySet xs s = Set.union s (Set.fromList xs) 

私は、これらはすべて(Monad m, Monoid o) => m o構造のためcomposFoldM利用composを作ることによって抽象化されることができるべきであると思います。 GADT Applicativeバージョンcomposを575/576ページのthe paperに掲載しています。私はこの構造のApplicativeインスタンスを作る必要があると思います。どうすればいい?それとも、私は間違った道を完全に下っていますか?

答えて

5

Constant出願人のData.Functor.Constanttransformersパッケージになります。hereが見つかります。

instance (Monoid a) => Applicative (Constant a) where 
    pure _ = Constant mempty 
    Constant x <*> Constant y = Constant (x `mappend` y) 

あなたは、あなたがhereを見つけることができます(transformersパッケージにも)ComposeData.Functor.Composeから使用して、他の応用的、とのConstantを構成することができます。

このApplicativeは、次のインスタンスがあります。

instance (Applicative f, Applicative g) => Applicative (Compose f g) where 
    pure x = Compose (pure (pure x)) 
    Compose f <*> Compose x = Compose ((<*>) <$> f <*> x) 

あなたはその後、ComposeApplicativeとあなたConstant応用的(のようなState)は、いくつかの状態と走行Monoidタリーの両方を維持することができます。

ComposeはこのApplicativeインスタンスを持っています。

もっと一般的には、これらのパターンについて詳しく説明しているThe Essence of the Iterator Patternという用紙を読んでください。

+0

これは私が必要とするもののように見えます!しかし、どうすればそれを実際に使用できますか? 'composFoldM f = getComposeのようなことをしようとしました。 compos(WrapMonadを構成するConst。f) 'しかしこれは動作しません。ファンクタを組み合わせる方法の例/説明はありますか? –

+0

私の神。私は最終的に試行錯誤してそれを仕上げました。私はこれがあなたが学ぶ方法だと思います!正しいことは 'composFoldM f = liftM getConstです。 unwrapMonad。 getCompose。コンポジット(WrapMonadを作成します。 :D –

+1

@CallumRogersそうですね!これはHaskellの素晴らしい点の1つです。型チェッカーは常にあなたを正しい解決策に導きます。 –

関連する問題