2013-08-17 27 views
5

对不起,可怕的标题。我正在尝试为Monad包装一个类型为MonoidApplicative实例。适用实例

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)' 

我意识到我上面写的东西可能没有任何意义。以下是上下文:我试图使用A pattern for almost compositional functions纸中所述的compos抽象。以这棵树(使用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) 

我想这些应该都能够通过使composFoldM使用compos(Monad m, Monoid o) => m o结构中抽象出来。因此,请使用the paper的第575/576页上的compos的GADT Applicative版本。我想我需要制作一个Applicative这个结构的实例。我将如何做到这一点?或者我完全走错了路?

回答

5

您希望Constant适用于Data.Functor.Constanttransformers包,其中您可以找到here

Applicative有以下实例:

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

然后,您可以编写Constant使用ComposeData.Functor.Compose(也在transformers包)任何其他应用性,你可以找到here

Compose有这个Applicative实例:

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

然后,您可以ComposeConstant应用性与任何其他Applicative(如State),以保持双方的一些状态和运行Monoid相符。

更一般地,您应该阅读纸张The Essence of the Iterator Pattern,其中更详细地讨论了这些模式。

+0

这看起来像我需要的东西!但我如何真正使用它?我试图做一些事情,比如'composFoldM f = getCompose。 compos(Compose。WrapMonad。Const。f)'但这不起作用。有没有关于如何组合仿函数的例子/解释? –

+0

我的天啊。我终于通过试验和改进完成了。我想这是你如何学习!正确的是'composFoldM f = liftM getConst。 unwrapMonad。 getCompose。 compos(Compose。WrapMonad。liftM Const。f)'。 :D –

+1

@CallumRogers完全正确!这是Haskell的好处之一:类型检查器将始终引导您朝向正确的解决方案。 –

相关问题