当前位置: 首页 > 知识库问答 >
问题:

其应用部分可以比单子部分更好地优化的单子示例

冯嘉荣
2023-03-14

在一次讨论中,我听说一些解析器的applicative接口的实现方式不同,比它们的monad接口更有效。原因是使用applicative,在运行整个有效的计算之前,我们预先知道所有的“效果”。对于单子,效果可能依赖于计算期间的值,所以这种优化是不可能的。

更新:只是澄清一下,这里我对不可能是单子的应用程序不感兴趣。问题是关于两者的东西。

共有1个答案

司承业
2023-03-14

另一个例子是严格的左折。您可以编写一个应用实例,它允许您组合折叠,以便在一次传递和常量空间中对数据执行结果折叠。但是,monad实例需要为每个绑定从数据的开始重新迭代,并将整个列表保留在内存中。

{-# LANGUAGE GADTs #-}

import Criterion.Main

import Data.Monoid
import Control.Applicative
import Control.Monad

import Prelude hiding (sum)

data Fold e r where
    Step :: !(a -> e -> a) -> !a -> !(a -> r) -> Fold e r
    Bind :: !(Fold e r) -> !(r -> Fold e s) -> Fold e s

data P a b = P !a !b

instance Functor (Fold e) where
    fmap f (Step step acc ret) = Step step acc (f . ret)
    fmap f (Bind fld g) = Bind fld (fmap f . g)

instance Applicative (Fold e) where
    pure a    = Step const a id
    Step fstep facc fret <*> Step xstep xacc xret = Step step acc ret where
        step (P fa xa) e = P (fstep fa e) (xstep xa e)
        acc = P facc xacc
        ret (P fa xa) = (fret fa) (xret xa)

    Bind fld g <*> fldx = Bind fld ((<*> fldx) . g)
    fldf <*> Bind fld g = Bind fld ((fldf <*>) . g)

instance Monad (Fold e) where
    return = pure
    (>>=) = Bind

fold :: Fold e r -> [e] -> r
fold (Step _ acc ret) [] = ret acc
fold (Step step acc ret) (x:xs) = fold (Step step (step acc x) ret) xs
fold (Bind fld g) lst = fold (g $ fold fld lst) lst

monoidalFold :: Monoid m => (e -> m) -> (m -> r) -> Fold e r
monoidalFold f g = Step (\a -> mappend a . f) mempty g

count :: Num n => Fold e n
count = monoidalFold (const (Sum 1)) getSum

sum :: Num n => Fold n n
sum = monoidalFold Sum getSum

avgA :: Fold Double Double
avgA = liftA2 (/) sum count

avgM :: Fold Double Double
avgM = liftM2 (/) sum count

main :: IO ()
main = defaultMain
    [ bench "Monadic"     $ nf (test avgM) 1000000
    , bench "Applicative" $ nf (test avgA) 1000000
    ] where test f n = fold f [1..n]

我把上面写的作为一个例子,所以它可能不是应用折叠和单子折叠的最佳实现,但是运行上面给了我:

benchmarking Monadic
mean: 119.3114 ms, lb 118.8383 ms, ub 120.2822 ms, ci 0.950
std dev: 3.339376 ms, lb 2.012613 ms, ub 6.215090 ms, ci 0.950

benchmarking Applicative
mean: 51.95634 ms, lb 51.81261 ms, ub 52.15113 ms, ci 0.950
std dev: 850.1623 us, lb 667.6838 us, ub 1.127035 ms, ci 0.950
 类似资料:
  • 正则表达式 说明 /\b([a-z]+) \1\b/gi 一个单词连续出现的位置 /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/ 将一个URL解析为协议、域、端口及相对路径 /^(?:Chapter|Section) [1-9][0-9]{0,1}$/ 定位章节的位置 /[-a-z]/ A至z共26个字母再加一个-号。 /ter\b/ 可匹配chapter,而不能termi

  • 我在通过VB.NET控制台应用程序向BambooHR API提交多部分表单时遇到了很多困难。我已经发布了我当前的代码以及下面文档中的一个示例请求,当我运行这个代码时,我得到了(400)个坏请求。我知道代码很乱,但我一直在努力让它工作。 如有任何帮助,我们将不胜感激。 下面是我的代码: 下面是文档中的示例请求:(链接:https://www.bamboohr.com/api/documentatio

  • 问题内容: 使用Mongoose可以一次性在一个(子)文档上设置多个属性吗?我正在尝试做的一个例子: 假设我有以下架构: 然后我想做: 通常,我可以使用运算符来实现此目的,但是我的问题是在此示例中是的子文档(嵌入式架构)。所以当我尝试去做 它替换了由标识的子文档实例。目前,我已经通过手动设置仅字段来“解决”它,但是我希望有一种更好的方法来做到这一点。 问题答案: 基于的字段以编程方式构建对象,以使

  • 我需要在Spring MVC中创建一个可以处理JSON和Multipart Form请求的方法。 这是我的方法的签名: ImageDTO类如下所示: 所以这个场景是我需要支持两个场景:1。从表单向上加载图像,其中内容类型为多部分表单(所有DTO成员均不为null)2。使用JSON上传图像,仅使用imageUrl。在本例中,请求正文如下所示: 当前的实现很好地处理了多部分请求,但在发送JSON时,I

  • 我使用BottomNavigationViewEx库在我的android应用程序中显示底部菜单栏,该库运行良好并修复了标准BottomNavigationView的许多缺点。 问题是,根据要求,我需要在菜单中显示7个选项,其中4个选项是对各自功能的直接访问,还有一个“更多”选项,该选项应该显示一个包含3个以上选项的子菜单(类似于一个工具栏,其中包含属性为showAsAction=“never”的项

  • 第十部分 因子分析(Factor analysis) 如果有一个从多个高斯混合模型(a mixture of several Gaussians)而来的数据集 $x^{(i)} \in R^n$ ,那么就可以用期望最大化算法(EM algorithm)来对这个混合模型(mixture model)进行拟合。这种情况下,对于有充足数据(sufficient data)的问题,我们通常假设可以从数据中