Applicative
变压器类在哪里?我想为applicative transformer stack in a previous answer使用变换器类,但它们似乎不存在。
即使基础结构不是Applicative
,transformers包和许多其他包都会包含保留Monad
结构的变换器。
快速浏览transformers
大多数变形金刚都有Applicative
个实例。
Applicative f => Applicative (Backwards f)
Applicative f => Applicative (Lift f)
Applicative (ContT r m)
Applicative m => Applicative (IdentityT m)
Applicative m => Applicative (ReaderT r m)
(Monoid w, Applicative m) => Applicative (WriterT w m)
(Applicative f, Applicative g) => Applicative (Compose f g)
(Applicative f, Applicative g) => Applicative (Product f g)
只有状态和替换的变换器(ExceptT
和MaybeT
)才需要Applicative
实例的基础monad。
(Functor m, Monad m) => Applicative (ExceptT e m)
(Functor m, Monad m) => Applicative (MaybeT m)
(Monoid w, Functor m, Monad m) => Applicative (RWST r w s m)
(Functor m, Monad m) => Applicative (StateT s m)
有Monad
变形金刚的课程。我可以看到某些东西可能需要这个Monad
约束,因为它不能在其他地方引入。
class MonadTrans t where
lift :: (Monad m) => m a -> t m a
Applicative
变形金刚的课程在哪里?
class ApTrans t where
liftAp :: (Applicative f) => f a -> t f a
或者只是普通的旧变形金刚(虽然我无法想象有任何法律规定)?
class Trans t where
liftAny :: f a -> t f a
由于仅在多态约束方面存在差异,因此这些类型类具有奇怪的方差模式。除了必须考虑无法解决约束的法律之外,任何Trans
实例的内容都应自动成为ApTrans
和MonadTrans
的实例,以及{{1}的实例应该自动成为ApTrans
的实例。
如果我们转到mtl库,那里的类也与MonadTrans
变换器堆栈不兼容。我熟悉的所有mtl类都有Applicative
约束。例如,这里是Monad
MonadReader
class Monad m => MonadReader r m | m -> r where
-- | Retrieves the monad environment.
ask :: m r
ask = reader id
-- | Executes a computation in a modified environment.
local :: (r -> r) -- ^ The function to modify the environment.
-> m a -- ^ @Reader@ to run in the modified environment.
-> m a
-- | Retrieves a function of the current environment.
reader :: (r -> a) -- ^ The selector function to apply to the environment.
-> m a
reader f = do
r <- ask
return (f r)
约束的目的是什么?它使许多上述变换器的Monad
和MonadReader
实例与MonadReader
变换器堆栈不兼容。
我会天真地写出像
这样的东西Applicative
甚至将class Reader r m | m -> r where
ask :: m r
local :: (r -> r) -> m a -> m a
拆分为单独的类。
local
没有class Reader r m | m -> r where
ask :: m r
class (Reader r m) => Local r m | m -> r where
local :: (r -> r) -> m a -> m a
实例, local
可能很难使用。没有Monad
约束的更有用的接口将类似于
Monad
是否存在没有class (Reader r m) => Local r m | m -> r where
local :: m (r -> r) -> m a -> m a
约束的现有变换器类,或者是否真的需要另一个变换器类库?
答案 0 :(得分:9)
与Monads不同,申请人在产品和作品下关闭,因此不需要特殊类别的东西,如变形金刚&#34;。这是一个小型图书馆:
data (*) f g x = P (f x) (g x) deriving Functor
data C f g x = C (f (g x)) deriving Functor
instance (Applicative f, Applicative g) => Applicative (f * g) where
pure a = P (pure a) (pure a)
P ff gf <*> P fx gx = P (ff <*> fx) (gf <*> gx)
instance (Applicative f, Applicative g) => Applicative (C f g) where
pure = C . pure . pure
C fgf <*> C fgx = C (liftA2 (<*>) fgf fgx)
此外,所有monad 都是 Applicatives所以我们应该能够重用该代码。遗憾的是,缺少Applicative-Monad子类型会使monadic代码更加排斥,而不是需要这样的代码。如果所有这些库都要求(Applicative m, Monad m)
约束,它本可以纠正,但它们不会。此外,考虑到你可能不得不写的频率
(MonadReader m, Monad m) => ...
Monad超类约束很方便。但我不确定它是否完全必要。
答案 1 :(得分:5)
正如J. Abrahamson所说,应用程序在产品和组成下是封闭的,因此不需要专用的变压器版本。但是,也没有必要推出自己的Applicative产品/组合类型,因为平台已经有这些:
Data.Functor.Compose
Data.Functor.Product
Data.Functor.Constant
Data.Functor.Identity
Control.Applicative.Lift
我发现更简单的方法是使用GeneralizedNewtypeDeriving
扩展名,因为这样你就可以定义类似这样的类型:
newtype MyType m a = MyType (Compose (Const m) (Reader m) a)
deriving (Functor, Applicative)
-- Plus a bunch of utility definitions to hide the use of Compose and generally
-- keep you sane...
Applicative工具集中另一个有用的工具是免费的applicative functor。我通常使用Edward Kmett's free
library's version,但如果您想要更少的依赖项,则可以轻松自行推送。
这些定义也很有用(虽然我欢迎有关命名方案的建议,特别是“I / O”位):
{-# LANGUAGE Rank2Types, TypeOperators #-}
import Control.Applicative
import Data.Functor.Compose
-- | A handy infix type synonym for 'Compose', which allows us to
-- stack 'Applicative's with less syntactic noise:
--
-- > type CalculationT s p f = Reader (Frame s p) :. Reader (Cell s p) :. f
-- > type Calculation s p = Calculation s p Identity
--
-- Note that 'Identity' and ':.' form something a type-level monoid
-- modulo @newtype@ equivalence. The following isomorphisms hold:
--
-- > f :. Identity ~= Identity :. f ~= f
-- > f :. g :. h ~= (f :. g) :. h
--
type f :. g = Compose f g
infixr :.
-- | Lift an action from the outer functor into the composite.
-- Alternative reading: append an 'Applicative' to the right of @f@.
liftO :: (Functor f, Applicative g) => f a -> (f :. g) a
liftO = Compose . fmap pure
-- | Lift an action from the inner functor into the composite.
-- Alternative reading: prepend an 'Applicative' to the left of @g@.
liftI :: Applicative f => g a -> (f :. g) a
liftI = Compose . pure
-- | Lift a natural transformation from @g@ to @h@ into a morphism
-- from @f :. g@ to @h :. g@.
hoistO :: (forall x. f x -> h x) -> (f :. g) a -> (h :. g) a
hoistO eta = Compose . eta . getCompose
-- | Lift a natural transformation from @g@ to @h@ into a morphism
-- from @f :. g@ to @f :. h@.
hoistI :: Functor f => (forall x. g x -> h x) -> (f :. g) a -> (f :. h) a
hoistI eta = Compose . fmap eta . getCompose