申请人撰写,monad没有.
上述陈述是什么意思?什么时候比其他人更好?
monads haskell functional-programming monad-transformers applicative
Hackage有几个monad变换器包:
(也许我错过了一些)
我们应该使用哪一个?
mtl是Haskell平台中的一个,但我一直听说reddit它是不酷的.
但无论如何,选择有什么不好,这不是一件好事吗?
好吧,我看到数据访问器的作者如何必须使所有这些满足流行的选择:
我想如果这种情况继续下去,例如几个竞争的箭头包演变,我们可能会看到类似:spoonklink-arrows-transformers,spoonklink-arrows-monadLib,spoonklink-tfArrows-transformers,spoonklink-tfArrows-monadLib,...
然后我担心如果spoonklink被分叉,Hackage将耗尽磁盘空间.:)
问题:
在什么情况下应该liftIO使用?当我使用时ErrorT String IO,该lift功能可以解除IO操作ErrorT,因此liftIO看起来多余.
到目前为止,我遇到的每个monad(可以表示为数据类型)都有相应的monad变换器,或者可以有一个.有这样一个不能有一个单子吗?或者所有monad都有相应的变压器?
通过对应于monad的变换器t,m我的意思t Identity是同构的m.当然,它满足monad变压器法则,并且t n是任何monad的monad n.
我希望看到每个monad都有一个证明(理想情况下是建设性的证明),或者没有一个证明(带证明)的特定monad的例子.我对更多面向Haskell的答案以及(类别)理论答案感兴趣.
作为后续问题,是有一个单子m是有两个不同的变压器t1和t2?也就是说,t1 Identity同构t2 Identity和m,但有一个单子n这样t1 n是不是同构t2 n.
(IO并且ST有一个特殊的语义,所以我不在这里考虑它们,让我们完全忽略它们.让我们只关注可以使用数据类型构造的"纯"monad.)
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通过迭代日志中的状态来"假装" 它.(显然这排除了改变步骤之间的状态,因为我们现在并没有真正"暂停"任何东西.)
在我的业务领域 - 金融机构的后台IT - 软件组件通常进行全局配置,记录其进度,进行某种错误处理/计算短路是很常见的...可以通过Haskell中的Reader-,Writer-,Maybe-monads等很好地建模,并与monad变换器一起组合.
但似乎存在一些缺点:monad变换器背后的概念非常棘手且难以理解,monad变换器导致非常复杂的类型签名,并且它们会造成一些性能损失.
所以我想知道:monad变形金刚在处理上述常见任务时是最佳做法吗?
我有一个问题,一堆monad变压器(甚至一个monad变压器)结束IO.一切都很好,除了在每次动作之前都使用电梯非常烦人!我怀疑这与此无关,但我想我还是会问.
我知道提升整个块,但如果代码实际上是混合类型怎么办?如果GHC投入一些语法糖(例如,<-$= <- lift),这不是很好吗?
我是Haskell的新手,但了解如何使用Monad变形金刚.然而,我仍然难以获得他们声称的优势,而不是将参数传递给函数调用.
基于wiki Monad Transformers Explained,我们基本上将Config对象定义为
data Config = Config Foo Bar Baz
Run Code Online (Sandbox Code Playgroud)
传递它,而不是用这个签名编写函数
client_func :: Config -> IO ()
Run Code Online (Sandbox Code Playgroud)
我们使用ReaderT Monad Transformer并将签名更改为
client_func :: ReaderT Config IO ()
Run Code Online (Sandbox Code Playgroud)
然后拉动Config只是一个电话ask.
函数调用从更改client_func c为runReaderT client_func c
精细.
但为什么这会使我的应用程序变得更简单?
1-我怀疑当你将许多功能/模块拼接在一起形成一个应用程序时,Monad变形金刚会感兴趣.但这就是我的理解停止的地方.有人可以请一些亮点吗?
2-我找不到任何关于如何在Haskell中编写大型模块化应用程序的文档,其中模块公开某种形式的API并隐藏它们的实现,以及(部分地)将其自己的状态和环境隐藏在其他模块中.有什么指针吗?
(编辑:真实世界Haskell声称"......这种方法[Monad变形金刚] ......扩展到更大的程序.",但没有明确的例子证明这种说法)
编辑关注Chris Taylor以下答案
克里斯完美地解释了为什么封装Config,State等等......在Transformer Monad中提供了两个好处:
getUserInput函数)Writer以提供更低级别功能的Logging)这是以更改所有功能的签名为代价的,以便它们在Transformer Monad中"运行".
所以问题1已完全涵盖.谢谢克里斯.
现在在这篇SO帖子中回答了问题2
每个其他monad都带有变压器版本,据我所知,变压器的概念是monad的通用扩展.跟随其他变形金刚的构建方式,IOT就像是
newtype IOT m a = IOT { runIOT :: m (IO a) }
Run Code Online (Sandbox Code Playgroud)
我可以在现场组成有用的应用程序:IOT Maybe可以执行IO操作,IOT []也可以不执行任何操作,可以构建一个稍后可以执行的列表sequence.
那么为什么Haskell中没有IO变压器呢?
(注意:我在Haskell Cafe上看过这篇文章,但对它没有多大意义.另外,ST转换器的Hackage页面在其描述中提到了一个可能相关的问题,但没有提供任何细节.)
有人可以提供一个超级简单(几行)monad变换器示例,这是非平凡的(即不使用Identity monad - 我理解).
例如,有人会如何创建一个执行IO并可以处理失败的monad(可能)?
什么是最简单的例子来证明这一点?
我已经浏览了一些monad变换器教程,他们似乎都使用State Monad或Parsers或者复杂的东西(对于newbee).我想看到一些比这简单的东西.我认为IO +也许会很简单,但我自己并不知道如何做到这一点.
我怎么能使用IO + Maybe monad堆栈?最重要的是什么?什么会在底部?为什么?
在什么样的用例中,人们想要使用IO + Maybe monad还是Maybe + IO monad?创造这样一个复合单子会有意义吗?如果是,何时以及为什么?