haskell - Are applicative transformers really superfluous? -
there lot of talk applicative
not needing own transformer class, this:
class apptrans t lifta :: applicative f => f -> t f
but can define applicative transformers don't seem compositions of applicatives! example sideeffectful streams:
data mstream f = mstream (f (a, mstream f a))
lifting performs side effect @ every step:
instance apptrans mstream lifta action = mstream $ (,) <$> action <*> pure (lifta action)
and if f
applicative, mstream f
well:
instance functor f => functor (mstream f) fmap fun (mstream stream) = mstream $ (\(a, as) -> (fun a, fmap fun as)) <$> stream instance applicative f => applicative (mstream f) pure = lifta . pure mstream fstream <*> mstream astream = mstream $ (\(f, fs) (a, as) -> (f a, fs <*> as)) <$> fstream <*> astream
i know practical purposes, f
should monad:
joins :: monad m => mstream m -> m [a] joins (mstream stream) = (a, as) <- stream aslist <- joins return $ : aslist
but while there monad
instance mstream m
, it's inefficient. (or incorrect?) applicative
instance useful!
now note usual streams arise special cases identity functor:
import data.functor.identity type stream = mstream identity
but composition of stream
, f
not mstream f
! rather, compose stream f a
isomorphic stream (f a)
.
i'd know whether mstream
composition of 2 applicatives.
edit:
i'd offer category theoretic viewpoint. transformer "nice" endofunctor t
on category c
of applicative functors (i.e. lax monoidal functors strength), natural transformation lifta
identity on c
t
. more general question useful transformers exist not of form "compose g
" (where g
applicative). claim mstream
1 of them.
great question! believe there 2 different parts of question:
- composing existing applicatives or monads more complex ones.
- constructing all applicatives/monads given starting set.
ad 1.: monad transformers essential combining monads. monads don't compose directly. seems there needs bit of information provided monad transformers tells how each monad can composed other monads (but information somehow present, see is there monad doesn't have corresponding monad transformer?).
on other hand, applicatives compose directly, see data.functor.compose. why don't need applicative transformers composition. they're closed under product (but not coproduct).
for example, having infinite streams data stream = cons (stream a)
, applicative g
, both stream (g a)
, g (stream a)
applicatives.
but though stream
monad (join
takes diagonal of 2-dimensional stream), composition monad m
won't be, neither stream (m a)
nor m (stream a)
monad.
furthermore can see, they're both different mstream g
(which close listt
done right), therefore:
ad 2.: can applicatives constructed given set of primitives? apparently not. 1 problem constructing sum data types: if f
, g
applicatives, either (f a) (g a)
won't be, don't know how compose right h <*> left x
.
another construction primitive taking fixed point, in mstream
example. here might attempt generalize construction defining like
newtype fix1 f = fix1 { unfix1 :: f (fix1 f) } instance (functor (f (fix1 f))) => functor (fix1 f) fmap f (fix1 a) = fix1 (fmap f a) instance (applicative (f (fix1 f))) => applicative (fix1 f) pure k = fix1 (pure k) (fix1 f) <*> (fix1 x) = fix1 (f <*> x)
(which requires not-so-nice undecidableinstances
) , then
data mstream' f g = mstream (f (a, g a)) type mstream f = fix1 (mstream' f)
Comments
Post a Comment