Monads可以做许多惊人的,疯狂的事情.他们可以创建具有值叠加的变量.它们可以允许您在计算之前访问未来的数据.它们可以让您编写破坏性更新,但不是真的.然后延续monad让你打破人们的思想!通常是你自己的.;-)
但这是一个挑战:你能制作一个可以暂停的单子吗?
data Pause s x instance Monad (Pause s) mutate :: (s -> s) -> Pause s () yield :: Pause s () step :: s -> Pause s () -> (s, Maybe (Pause s ()))
该Pause单子是一种状态的单子(因此mutate,具有明显的语义).通常情况下,像这样的monad具有某种"运行"功能,它运行计算并将您送回最终状态.但Pause它是不同的:它提供了一个step函数,它运行计算直到它调用魔法yield函数.这里计算暂停,返回给调用者足够的信息以便稍后恢复计算.
额外的awesomness:允许调用者修改step调用之间的状态.(例如,上面的类型签名应该允许这样做.)
使用案例:编写执行复杂操作的代码通常很容易,但是要将其转换为也在其操作中输出中间状态的总PITA .如果您希望用户能够在执行过程中途改变某些内容,那么事情变得非常复杂.
实施思路:
显然它可以用线程,锁和IO.但我们能做得更好吗?;-)
继续monad疯狂的东西?
也许是某种编写器monad,yield只记录当前状态,然后我们可以step通过迭代日志中的状态来"假装" 它.(显然这排除了改变步骤之间的状态,因为我们现在并没有真正"暂停"任何东西.)
我正在开发一个项目,除其他外,涉及数据库访问层.非常正常,真的.在之前的项目中,合作者鼓励我将Free Monads概念用于数据库层,所以我做到了.现在,我正在尝试在我的新项目中决定我获得了什么.
在之前的项目中,我有一个看似相似的API.
saveDocument :: RawDocument -> DBAction ()
getDocuments :: DocumentFilter -> DBAction [RawDocument]
getDocumentStats :: DBAction [(DocId, DocumentStats)]
Run Code Online (Sandbox Code Playgroud)
大约二十个这样的公共职能.为了支持它们,我有了DBAction数据结构:
data DBAction a =
SaveDocument RawDocument (DBAction a)
| GetDocuments DocumentFilter ([RawDocument] -> DBAction a)
| GetDocumentStats ([(DocId, DocumentStats)] -> DBAction a)
| Return a
Run Code Online (Sandbox Code Playgroud)
然后是monad实现:
instance Monad DBAction where
return = Return
SaveDocument doc k >>= f = SaveDocument doc (k >>= f)
GetDocuments df k >>= f = GetDocuments df (k >=> f)
Run Code Online (Sandbox Code Playgroud)
然后是口译员.然后是实现每个不同查询的原始函数.基本上,我觉得我有大量的胶水代码.
在我当前的项目中(在一个完全不同的领域),我已经为我的数据库添加了一个非常普通的monad: …
我们从类别理论中知道,并非Set中的所有endofunctors都承认一个免费的monad.规范的反例是powerset仿函数.
但是Haskell可以将任何仿函数变成一个免费的monad.
data Free f a = Pure a | Free (f (Free f a))
instance Functor f => Monad (Free f) where
return = Pure
Pure a >>= f = f a
Free m >>= f = Free ((>>= f) <$> m)
Run Code Online (Sandbox Code Playgroud)
是什么让这个构造适用于任何Haskell仿函数但在Set中分解?
我一直在玩Cofree,并且不能完全理解它.
例如,我想Cofree [] Num在ghci中玩,并且不能得到任何有趣的例子.
例如,如果我构造一个Cofree类型:
let a = 1 :< [2, 3]
Run Code Online (Sandbox Code Playgroud)
我希望extract a == 1,但我得到这个错误:
No instance for (Num (Cofree [] a0)) arising from a use of ‘it’
In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it
Run Code Online (Sandbox Code Playgroud)
还有一种:
extract a :: (Num a, Num (Cofree [] a)) => a
Run Code Online (Sandbox Code Playgroud)
我可以得到一些简单的例子,甚至是琐碎的,如何使用Cofree有,比方说,函子:[],或者Maybe,或者Either,演示
extractextendunwrapduplicate?Cross发布:https: …
在对文件Free说:
许多常见的单子出现为免费单子,
- 鉴于
data Empty a,Free Empty与Identitymonad 同构.- Free
Maybe可用于建模偏好monad,其中每个图层表示运行计算的时间更长.
还有哪些monad可以使用Free?
我只想到一个:我相信Free (Const e)是同构的Either e.
编辑:哪些monad 不能用于表达Free?为什么?
在Haskell中创建monad 时,是否有任何关于何时使用延续传递样式与密度和反射而没有悔恨的经验法则?
举个例子,我将使用一个简单的协程monad.如果您以前从未见过这个,可能需要查看Monad.Reader Issue 19中的"Coroutine Pipelines"文章或管道库.可以在此存储库中找到以下示例的完整代码.
正常
这只是一个定义为数据类型的普通monad:
data FooM i o a
= Await (i -> FooM i o a)
| Yield o (FooM i o a)
| Done a
Run Code Online (Sandbox Code Playgroud)
这种风格被广泛用于Haskell生态系统.这种风格的一个例子是Proxy来自的数据类型pipes.
延续传球风格(CPS)
这类似于普通样式,但每个数据构造函数都成为延续的参数:
newtype FooCPS i o a = FooCPS
{ runFooCPS
:: forall r.
((i -> FooCPS i o a) -> r)
-> (o -> FooCPS i o a -> …Run Code Online (Sandbox Code Playgroud)我想我为提出了一个有趣的“ zippy” Applicative实例Free。
data FreeMonad f a = Free (f (FreeMonad f a))
| Return a
instance Functor f => Functor (FreeMonad f) where
fmap f (Return x) = Return (f x)
fmap f (Free xs) = Free (fmap (fmap f) xs)
instance Applicative f => Applicative (FreeMonad f) where
pure = Return
Return f <*> xs = fmap f xs
fs <*> Return x = fmap ($x) fs
Free fs <*> Free xs = Free $ …Run Code Online (Sandbox Code Playgroud) 可以为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 …
free-monad ×10
haskell ×10
monads ×8
applicative ×1
comonad ×1
coroutine ×1
dsl ×1
functor ×1
operational ×1
reflection ×1
tree ×1