可以为FreeT/ProgramT创建的monad变换器提供类似mtl的机制吗?
我对历史的理解如下.曾几何时,monad变压器被发明了.然后人们开始在另一个上堆叠monad变换器,然后发现插入lift到处都很烦人.然后有几个人发明了monad类,所以我们可以ask :: m r在任何monad中m这样做MonadReader r m.这可以通过让每个monad类穿透每个monad变换器来实现
(Monoid w, MonadState s m) => MonadState s (WriterT w m)
MonadWriter w m => MonadWriter w (StateT s m)
你需要为每对monad变换器提供这样的实例声明对,所以当有n个 monad变换器时,你需要n ^ 2个成本.然而,这不是一个大问题,因为人们将主要使用预定义的monad并且很少创建自己的monad.到目前为止,我理解这个故事,并且在下面的问答中也详细说明:
然后我的问题是新的免费monad http://hackage.haskell.org/package/free和操作monads http://hackage.haskell.org/package/operational.它们允许我们编写自己的DSL并将其用作monad,只需将语言定义为某种代数data类型(Operational甚至不需要Functor实例).好消息是我们可以免费获得monad和monad变换器; 那么monad课怎么样?坏消息是"我们很少定义我们自己的monad变换器"的假设不再成立.
为了解这个问题,我做了两个ProgramT,让它们相互渗透;
https://github.com/nushio3/practice/blob/master/operational/exe-src/test-05.hs
该operational包不支持monad类,所以我采用了另一个实现minioperational并将其修改为我需要的工作; https://github.com/nushio3/minioperational
不过,我需要专门的实例声明
instance (Monad m, Operational ILang m) => Operational ILang (ProgramT SLang m) where
因为以下形式的一般声明会导致不可判定的实例.
instance …
给定一个免费的monad DSL,例如:
data FooF x = Foo String x
| Bar Int x
deriving (Functor)
type Foo = Free FooF
Run Code Online (Sandbox Code Playgroud)
并随机翻译Foo:
printFoo :: Foo -> IO ()
printFoo (Free (Foo s n)) = print s >> printFoo n
printFoo (Free (Bar i n)) = print i >> printFoo n
Run Code Online (Sandbox Code Playgroud)
在我看来,应该可以在printFoo的每个迭代中散布一些东西,而无需手动操作:
printFoo' :: Foo -> IO ()
printFoo' (Free (Foo s n)) = print s >> print "extra info" >> printFoo' n
printFoo' (Free (Bar i n)) = print …Run Code Online (Sandbox Code Playgroud) 我正在学习Scala中的Free monad,我已经汇总了一个代数的简单例子,我可以使用猫将其升级为Free monad.
这是我的代数
sealed trait ConsultationOp[A]
object consultation {
case class Create(c: Consultation) extends ConsultationOp[Unit]
case class Get(s: ConsultationId) extends ConsultationOp[Option[Consultation]]
}
Run Code Online (Sandbox Code Playgroud)
我可以像使用它一样
def app = for {
c <- consultation.Create(Consultation("123", "A consultation"))
_ <- consultation.Get(c._id)
} yield ()
def interpreters = ConsultationInterpreter or UserInterpreter
app.foldMap(interpreters)
Run Code Online (Sandbox Code Playgroud)
当从提升ConsultationOp到Free隐式执行.
(缺少很多细节,完整的工作实现在这里:https://github.com/gabro/free-api)
到目前为止一切都那么好,但是如果我需要提取返回的可选值呢consultation.Get?
首先想到的是monad变换器,即类似的东西
def app = for {
c <- consultation.Create(Consultation("123", "A consultation")).liftM[OptionT]
d <- OptionT(consultation.Get(c._id))
_ <- doSomethingAConsultation(d)
} yield () …Run Code Online (Sandbox Code Playgroud) 该streaming套餐提供了一项zipsWith功能
zipsWith
:: (Monad m, Functor h)
=> (forall x y. f x -> g y -> h (x, y))
-> Stream f m r -> Stream g m r -> Stream h m r
Run Code Online (Sandbox Code Playgroud)
还有一个稍微简化的版本,
zipsWith'
:: Monad m
=> (forall x y p. (x -> y -> p) -> f x -> g y -> h p)
-> Stream f m r -> Stream g m r -> Stream h m r
Run Code Online (Sandbox Code Playgroud)
这些可以很容易地 …
我想我已经大致了解了免费monad是什么,但我想有一个更好的方式来形象化它.
有意义的是,自由岩浆只是二叉树,因为它可以像你一样"一般"而不会丢失任何信息.
同样,有意义的是,免费幺半群只是列表,因为操作顺序无关紧要.现在在"二叉树"中存在冗余,因此如果有意义的话,您可以将其展平.
有意义的是,自由群体看起来像分形,出于类似的原因:https://en.wikipedia.org/wiki/Cayley_graph#/media/File: Cayley_graph_of_F2.svg 并且为了得到其他群体,我们只是识别不同的元素该群体是"相同的",我们得到其他群体.
我应该如何形象化免费的monad?现在,我只是把它想象成你能想象的最通用的抽象语法树.这本质上是吗?还是我过度简化了?
同样,从免费monad到列表或其他monad,我们会失去什么?我们认为什么是"相同"?
我感谢所有能够阐明这一点的评论.谢谢!
我最近一直在教自己关于免费套餐中的Freemonad ,但我遇到了一个问题.我想为不同的库提供不同的免费monad,基本上我想为不同的上下文构建DSL,但我也希望能够将它们组合在一起.举个例子:
{-# LANGUAGE DeriveFunctor #-}
module TestingFree where
import Control.Monad.Free
data BellsF x
= Ring x
| Chime x
deriving (Functor, Show)
type Bells = Free BellsF
data WhistlesF x
= PeaWhistle x
| SteamWhistle x
deriving (Functor, Show)
type Whistles = Free WhistlesF
ring :: Bells ()
ring = liftF $ Ring ()
chime :: Bells ()
chime = liftF $ Chime ()
peaWhistle :: Whistles ()
peaWhistle = liftF $ PeaWhistle ()
steamWhistle …Run Code Online (Sandbox Code Playgroud) 请考虑以下类型签名:
data Foo x = Foo {
name :: String
, reader :: String -> x
}
instance Functor Foo where
fmap f (Foo n r) = Foo n $ f . r
Run Code Online (Sandbox Code Playgroud)
现在,我显示来自自然转化Foo到optparse-applicative的Parser类型:
import qualified Options.Applicative as CL
mkParser :: Foo a -> CL.Parser a
mkParser (Foo n _) = CL.option CL.disabled ( CL.long n )
Run Code Online (Sandbox Code Playgroud)
(好吧,它有点无用,但它可以用于讨论).
现在我Bar成为免费的替代函子Foo:
type Bar a = Alt Foo a
Run Code Online (Sandbox Code Playgroud)
鉴于这是一个免费的仿函数,我应该能够mkParser从一个自然转变Bar …
该免费MonadPlus定义为
data Free f a = Pure a | Free (f (Free f a)) | Plus [Free f a]
Run Code Online (Sandbox Code Playgroud)
已使用以下注释(changelog)在free 4.6 中删除:
删除了
Control.MonadPlus.Free.使用FreeT f []来代替,而结果将是守法的.
问题是什么,特别是哪些法律没有?
我正在玩弄类似自由的想法,并发现了这个:
{-# LANGUAGE RankNTypes #-}
data Monoid m = Monoid { mempty :: m, mappend :: m -> m -> m }
data Generator a m = Generator { monoid :: Monoid m, singleton :: a -> m }
newtype Free f = Free { getFree :: forall s. f s -> s }
mkMonoid :: (forall s. f s -> Monoid s) -> Monoid (Free f)
mkMonoid f = Monoid {
mempty = Free (mempty . f),
mappend = …Run Code Online (Sandbox Code Playgroud) 是x >>= f相当于retract (liftF x >>= liftF . f)?
也就是说,一个免费monad构建的monad实例是一个Functor,它也是一个Monad将拥有与原Monad相同的monad实例?