新类型比枚举更快吗?

2024-01-28

根据本文 http://www.haskell.org/haskellwiki/Performance/Data_types,

就 GHC 而言,枚举不算作单构造函数类型,因此当用作严格构造函数字段或严格函数参数时,它们不会从解包中受益。这是 GHC 的缺陷,但可以解决。

相反,建议使用新类型。但是,我无法使用以下代码验证这一点:

{-# LANGUAGE MagicHash,BangPatterns #-}
{-# OPTIONS_GHC  -O2 -funbox-strict-fields -rtsopts -fllvm -optlc --x86-asm-syntax=intel #-}
module Main(main,f,g)
where       
import GHC.Base  
import Criterion.Main

data D = A | B | C
newtype E = E Int deriving(Eq)

f :: D -> Int#
f z | z `seq` False = 3422#
f z = case z of
  A -> 1234#
  B -> 5678#
  C -> 9012#

g :: E -> Int#
g z | z `seq` False = 7432#
g z = case z of
  (E 0) -> 2345#
  (E 1) -> 6789#
  (E 2) -> 3535#

f' x = I# (f x)
g' x = I# (g x)

main :: IO ()
main = defaultMain [ bench "f" (whnf f' A) 
                   , bench "g" (whnf g' (E 0)) 
                   ]

查看汇编代码,枚举 D 的每个构造函数的标记实际上已解包并直接硬编码在指令中。此外,函数f缺少错误处理代码,并且速度快 10% 以上g。在更现实的情况下,我在将枚举转换为新类型后也经历了速度减慢。谁能给我一些关于这个的见解?谢谢。


这取决于用例。对于您拥有的功能,预计枚举性能会更好。基本上,三个构造函数D become Ints resp. Int#当严格性分析允许时,并且 GHC 知道它已静态检查参数只能具有三个值之一0#, 1#, 2#,因此不需要插入错误处理代码f. For E,没有给出仅三个值之一可能的静态保证,因此需要添加错误处理代码g,这会显着减慢速度。如果你改变定义g这样最后一个案例就变成了

E _ -> 3535#

差异完全或几乎完全消失(我得到了 1% - 2% 更好的基准)f尽管如此,但我还没有进行足够的测试来确定这是否是真正的差异或基准测试的产物)。

但这不是 wiki 页面讨论的用例。它所说的是当类型是其他数据的组件时,例如,将构造函数解包到其他构造函数中。

data FooD = FD !D !D !D

data FooE = FE !E !E !E

然后,如果编译为-funbox-strict-fields, 他们三个Int#s 可以被解压到构造函数中FooE,所以你基本上会得到相当于

struct FooE {
    long x, y, z;
};

while the fields of FooD have the multi-constructor type D and cannot be unpacked into the constructor FD(1), so that would basically give you

struct FooD {
    long *px, *py, *pz;
}

这显然会产生重大影响。

我不确定单构造函数参数的情况。对于包含数据的类型(例如元组)来说,这具有明显的优势,但我不知道这如何应用于普通枚举,在普通枚举中,您只有一个case将工人和包装机分开(对我来说)是没有意义的。

无论如何,工作者/包装器转换并不是单一构造函数的事情,构造函数专门化可以为具有很少构造函数的类型提供相同的好处。 (创建多少个构造函数专业化取决于-fspec-constr-count.)


(1) That might have changed, but I doubt it. I haven't checked it though, so it's possible the page is out of date.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

新类型比枚举更快吗? 的相关文章

  • 为什么这会导致 Haskell Conduit 库内存泄漏?

    我有一个conduit https hackage haskell org package conduit管道处理长文件 我想每 1000 条记录为用户打印一份进度报告 所以我这样写 Every n records perform the
  • 在 Haskell 中对单位的组成(例如英寸、美元等)进行建模

    跟进自我之前的一个问题 https stackoverflow com q 73375273 222529 我问如何创建一个可以对单元进行建模的类型 例如Inch 作为 Haskell 中的一种类型 我现在面临的问题是如何对该单元和其他单元
  • 应用交换律

    带有效果的应用程序编程 http staff city ac uk ross papers Applicative html麦克布莱德和帕特森的论文提出了互换法 u lt gt pure x pure f gt f x lt gt u 为了
  • 不同 hs 文件中的函数分离时堆栈空间溢出

    我有一个巨大的 haskell 文件 它编译和运行没有任何问题 我想将一些函数和类型定义放在通用 hs 文件中的单独模块中 然后将其导入我的主模块中 虽然主程序编译时没有任何错误 它还编译导入的模块 但当我尝试运行它时 出现堆栈空间溢出 I
  • 可以通过Data.Function.fix来表达变形吗?

    我有这个可爱的fixana这里的函数执行速度比她的姐妹快 5 倍左右ana 我有一个criterion报告支持我这一点 ana alg Fix fmap ana alg alg fixana alg fix f gt Fix fmap f
  • Haskell 中的常量变量声明

    要声明常量变量 我可以在 Ruby 中执行以下操作 class COLOR RED 10 BLUE 20 GREEM 30 end COLOR RED回报10 COLOR BLUE回报20 等等 我如何在 Haskell 中实现这一点 我想
  • 'lens' 的阴谋集团依赖性解析失败

    我刚刚做了一个阴谋更新并尝试从 hackage 安装 lens 这给了我以下错误 cabal install j lens Resolving dependencies Configuring dlist 0 7 0 1
  • 谁能解释一下 GHC 对 IO 的定义吗?

    标题非常自我描述 但有一个部分引起了我的注意 newtype IO a IO State RealWorld gt State RealWorld a 剥离newtype 我们得到 State RealWorld gt State Real
  • 为什么haskell中的递归列表这么慢?

    我对 Haskell 很陌生 我在 Haskell 中定义了一个函数 febs Integral a gt a gt a febs n n lt 0 0 n 1 1 n 2 1 otherwise febs n 1 febs n 2 但是
  • 如何组合过滤条件

    过滤器类函数接受一个条件 a gt Bool 并在过滤时应用它 当您有多个条件时 使用过滤器的最佳方法是什么 使用了应用函数 liftA2 而不是 liftM2 因为出于某种原因我不明白 liftM2 在纯代码中如何工作 liftM2 组合
  • 反应性香蕉时间延迟

    我已经查阅了文档反应香蕉 http hackage haskell org package reactive banana 而且我找不到指定明确时间延迟的方法 举例来说 我想采取Event t a并将其所有发生的事件移至未来 1 秒 或获取
  • 有没有办法在 Emacs 中使用 Djinn 自动生成 Haskell 代码?

    标题几乎说明了一切 我正在寻找这样的东西 f Int gt Bool gt Int f body Djinn 可以使用定理证明来通过证明该类型存在来生成此类函数的代码 我想知道 是否有现有的方法可以从 Emacs 中获取此功能 因此 我不需
  • 什么是阴谋地狱?

    在阅读有关 阴谋地狱 的内容时 我有点困惑 因为这个词的含义太多了 我猜最初 Cabal Hell 指的是钻石依赖问题 该问题是通过限制构建计划在每个构建计划中只有任何包的单个版本来解决的 一个包的两个不同版本不能存在于单个构建计划中 正如
  • Haskell 和 Idris 之间的区别:类型宇宙中运行时/编译时的反映

    因此 在 Idris 中 编写以下内容是完全有效的 item b Bool gt if b then Nat else List Nat item True 42 item False 1 2 3 cf https www youtube
  • Haskell 中的类型化抽象语法和 DSL 设计

    我正在 Haskell 中设计 DSL 我想要进行赋值操作 像这样的东西 下面的代码只是为了在有限的上下文中解释我的问题 我没有类型检查 Stmt 类型 data Stmt forall a Assign String Exp a Assi
  • 简单的秒差距示例会产生类型错误

    我正在尝试编译这个简单的秒差距代码 import Text Parsec simple letter 但我不断收到此错误 No instance for Stream s0 m0 Char arising from a use of let
  • 如何避免编写这种类型的 Haskell 样板代码

    我经常遇到这种情况 这很烦人 假设我有一个 sum 类型 它可以保存一个实例x或一堆其他无关的事情x data Foo x X x Y Int Z String other constructors not involving x 要声明
  • Haskell cabal:我刚刚安装了软件包,但现在找不到软件包

    在这里 http haskell org haskellwiki Cabal Install I just installed packages 2C but now the packages are not found这是我可以找到我正在
  • 是否有适用于 Haskell 或 Scala 等函数式语言的 LL 解析器生成器?

    我注意到明显缺乏用函数式语言创建解析器的 LL 解析器 我一直在寻找但没有成功的理想发现是为 ANTLR 风格的 LL 语法生成 Haskell 解析器 语法的模小数重新格式化 并且令我惊讶的是 每个最后一个解析器生成器都具有函数我发现的语
  • 用纯函数式语言保持状态

    我正在尝试弄清楚如何执行以下操作 假设您正在开发直流电机的控制器 您希望让它以用户设置的特定速度旋转 def set point ref sp 90 while true let curr read speed controller set

随机推荐

  • 使用 R 将列名称插入其值

    我需要将列名称 部门插入其值中 我有这样的代码 Department lt c Store1 Store2 Store3 Store4 Store5 Department2 lt c IT1 IT2 IT3 IT4 IT5 x lt c 1
  • 避免重复输入 mysql 数据库的最佳方法

    我有一个包含 3 列的表 id pk pageId fk 名称 我有一个 php 脚本 它将大约 5000 条记录转储到表中 其中大约一半是重复的 具有相同的 pageId 和名称 pageId 和名称的组合应该是唯一的 当我在 php 中
  • 使用预填充表单,仅提交更改的字段

    我有一个使用选择和文本输入的 html 表单 该表单预先填充了默认值 如何仅提交用户更改默认值的输入 请注意 该页面将存储在空间有限的嵌入式系统中 因此不可能使用 javascript 库 示例 HTML
  • 我正在与 requirejs 优化器和非 AMD 模块作斗争

    我正在与 requirejs 优化器作斗争 如果我只是将其加载到浏览器中而不进行优化 则该代码将起作用 如果我运行优化器 我会得到 ENOENT no such file or directory C Users dev checkout
  • ServletContainerInitializer 中 contextDestroyed() 的等价物是什么?

    我必须创建一个实现的类ServletContextListener https docs oracle com javaee 7 api javax servlet ServletContextListener html在Tomcat初始化
  • 模板中的 Latex 指令导致“unicode 转义错误”

    我想在 play Framework 2 0 模板中包含一些 LaTEX 代码 即 usepackage T1 fontenc usepackage latin9 inputenc usepackage babel 当然玩抱怨error i
  • 当属性名称包含空格和保留字时,将 JSON 映射到 C# 类

    我正在使用 REST API 服务 在服务响应 JSON 中 存在包含空格和保留字的属性名称 我试图将其映射到 C 类 但无法分配与字段名称相同的属性名称 目前 只有当字段的 JSON 属性和 C 类名完全匹配时 映射才会成功 否则该值将如
  • 如何仅使用 math.h 将双精度数转换为字符串?

    我正在尝试将双精度数转换为本机 NT 应用程序中的字符串 即仅依赖于ntdll dll 不幸的是 ntdll 的版本vsnprintf不支持 f等 迫使我自己实现转换 之前所提ntdll dll只出口其中的一小部分math h功能 floo
  • 如何在单个浏览器页面上向 Dash 应用程序添加多个图表?

    如何在同一页面上添加多个图中显示的图表 我试图将 html Div 组件添加到以下代码中以更新页面布局 以在单页上添加更多图形 但这些新添加的图形不会显示在页面上 只有旧图形显示在图片中可见 我应该修改什么元素 比如说在浏览器上的破折号应用
  • maven-shade-plugin 报告:创建着色 jar 时出错:...target/classes(是一个目录)

    当使用 m2eclipse 工具在 eclipse 中为配置为以下项目的项目运行 Maven 构建时Maven 阴影插件 https maven apache org plugins maven shade plugin 构建失败并显示以下
  • ResponseEntity 不接受文本/csv:Spring Boot

    我正在尝试创建一个接受 CSV 和 json 正文请求等文件的 API 我尝试使用ResponseEntitySpring Boot 中的对象 端点如下所示 PostMapping value csv consumes MediaType
  • 左侧 div 在 bootstrap 中未正确对齐[重复]

    这个问题在这里已经有答案了 我的代码中已经有粘性标头 我正在尝试在左侧添加一个粘性 div 最初看起来不错 当我尝试滚动内容时 布局正在改变 此外 在最小尺寸 移动尺寸 时 左侧 div 未正确对齐 请建议 var onResize fun
  • 如何通过 RxJs 合并或 groupBy toPromise?

    我有以下方法返回结果 如下所示 result status 200 status 200 status 400 我需要使用状态值对结果进行分组 并且对于上面的示例结果仅返回 2 个结果 而不是 3 个 update this demoSer
  • 这个Makefile 有什么问题吗?

    当我在以下 Makefile 上运行 make all 时 出现此错误 Makefile 5 缺少分隔符 停止 这是什么问题以及如何修复它 LEX lex YACC yacc CC gcc calcu y tab o lex yy o CC
  • GCC 左移溢出

    下面的小程序在 Mac 上使用 GCC 版本 4 2 1 Apple Inc build 5664 非常尴尬 include
  • Node+Express+MongoDB Native Client 性能问题

    我正在使用 MongoDB 测试 Node js ExpressJS Fastify Python Flask 和 Java 带有 webflux 的 Spring Boot 的性能 我将所有这些示例应用程序相继托管在同一台服务器上 因此所
  • 如何调试 GLSL 着色器?

    我需要调试 GLSL 程序 但我不知道如何输出中间结果 是否可以使用 GLSL 进行一些调试跟踪 例如使用 printf 而不使用像 glslDevil 这样的外部软件 您无法轻松地从 GLSL 内部与 CPU 进行通信 使用 glslDe
  • 如何仅显示一次网站预加载器

    我向我的网站添加了预加载器 每次访问该网站时都会播放预加载器动画 我希望它在每次访问域名时只播放一次 任何点击网站上的主页按钮或浏览器中的后退按钮我希望跳过预加载器 我希望它在任何时候在新选项卡或新浏览器窗口中打开时都显示出来 我尝试添加c
  • Python 日志记录:覆盖日志时间

    下列的Python 的文档 http docs python org library logging html logging Formatter formatTime 我正在尝试覆盖logging Formatter converter以
  • 新类型比枚举更快吗?

    根据本文 http www haskell org haskellwiki Performance Data types 就 GHC 而言 枚举不算作单构造函数类型 因此当用作严格构造函数字段或严格函数参数时 它们不会从解包中受益 这是 G