Cal*_*ers 5 monads haskell applicative monoids gadt
抱歉可怕的头衔.我正在尝试创建Applicative
一个Monad
包装类型的实例Monoid
.
instance (Monad m, Monoid o) => Applicative (m o) where
pure x = return mempty
xm <*> ym = do
x <- xm
y <- ym
return $ x `mappend` y
Run Code Online (Sandbox Code Playgroud)
这不起作用; 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)'
Run Code Online (Sandbox Code Playgroud)
我意识到我上面写的内容可能毫无意义.这是上下文:我正在尝试使用compos
文章中描述的抽象几乎是组合函数的模式.拿这棵树(使用GADT版本compos
;我已经简化了很多):
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
Run Code Online (Sandbox Code Playgroud)
我将编写许多函数,这些函数在树中下降并返回一个说错误列表或一组字符串,同时还需要状态(如绑定环境),例如:
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)
Run Code Online (Sandbox Code Playgroud)
我想这些应该都能够通过使被抽象出来composFoldM
使用compos
的(Monad m, Monoid o) => m o
结构.因此,请使用本文第575/576页上的GADT Applicative
版本.我想我需要创建一个这种结构的实例.我该怎么做?还是我完全走错了路?compos
Applicative
您希望Constant
从应用性Data.Functor.Constant
的transformers
包,你可以找到这里.
这Applicative
有以下实例:
instance (Monoid a) => Applicative (Constant a) where
pure _ = Constant mempty
Constant x <*> Constant y = Constant (x `mappend` y)
Run Code Online (Sandbox Code Playgroud)
然后Constant
,您可以使用Compose
from Data.Functor.Compose
(也在transformers
包中)使用任何其他应用程序,您可以在此处找到它们.
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)
Run Code Online (Sandbox Code Playgroud)
然后你可以和其他任何人一起使用Compose
你的Constant
应用程序Applicative
(比如State
)保持一些状态和运行Monoid
记录.
更一般地说,您应该阅读论文"迭代器模式的本质",它将更详细地讨论这些模式.