haskell - 用newtype构造函数映射有什么作用
问题描述
在思考类型fmap Sum
的第 8 章中,我了解到
fastSum :: [Int] -> Int
fastSum = getSum . mconcat . fmap Sum
有O(n)
运行时成本,而使用coerce
反而避免了这种开销。
我知道newtype
s 没有表示开销,但我不明白将 newtype 构造函数映射到列表的运行时效果是什么。我认为这只会产生编译时开销,而且应该只是O(1)
,因为编译器只需要知道fmap SomeNewtypeCtr
表达式的类型。
解决方案
由于优化,很难理解 Haskell 在这种情况下究竟做了什么。Haskell 只规定结果是什么,而不是如何获得。
一些可能性:
fmap Sum
执行列表扫描,并复制每个单元格和每个元素;fmap Sum
执行列表扫描,并复制每个单元格但不复制元素(新单元格指向旧元素);fmap Sum
根本不扫描列表并自动优化为无操作。
我尝试了 godbolt.org来检查生成的核心和程序集。请注意,它仍然使用旧的 GHC 8.6.2。尽管如此,我还是打开了优化 ( -O2
) 并编译了
foo :: [Int] -> [Sum Int]
foo = fmap Sum
并获得
foo = Example.foo1 `cast` (.....)
Example.foo1 = \ (v_a1iF :: [Int]) -> v_a1iF
因此foo
成为恒等函数,适当强制,产生程序集
movq %r14,%rbx
andq $-8,%rbx
jmp *(%rbx)
粗略地说,这应该相当于 GHC 运行时系统中的立即返回。
结论:Data.Coerce.coerce
非常好,因为它确保了无操作,但即使是普通的 Haskell,在优化后也可以非常高效。
推荐阅读
- java - Java UI 项目的外观和感觉 FlatLaf
- python - pythonlinkedlist删除元组
- swiftui - 如何在 SwiftUI 中使用(不同的)尺寸约束视图屏蔽视图?
- python - 如何摆脱弃用警告?
- gnu-screen - 屏幕在 NetBSD 上失败,报告“poll: Invalid argument”
- javascript - 如何将子数组的内容转换为父数组
- javascript - 在 redux-saga-firebase 中获取集合参考
- javascript - 使用反应添加到购物车功能
- c# - ASP.NET SPA 中的 Azure AD 实现
- html - 如何通过jquery附加嵌套的div?