使用 newtype 构造函数映射的效果是什么

Dam*_*les 9 haskell newtype

在第8章与思维类型我了解到fmap Sum的一部分

fastSum :: [Int] -> Int
fastSum = getSum . mconcat . fmap Sum
Run Code Online (Sandbox Code Playgroud)

O(n)运行时成本,而使用coerce则避免了这种开销。

我知道newtypes 没有表示开销,但我不明白的是将 newtype 构造函数映射到列表上的运行时效果是什么。我认为这只会有编译时开销,它应该只是O(1),因为编译器只需要知道fmap SomeNewtypeCtr表达式的类型。

chi*_*chi 7

由于优化,很难理解 Haskell 在这种情况下到底做了什么。Haskell 只要求结果是什么,而不是如何获得结果。

一些可能性:

  • fmap Sum 执行列表扫描,并复制每个单元格和每个元素;
  • fmap Sum 执行列表扫描,并复制每个单元格但不复制元素(新单元格指向旧元素);
  • fmap Sum 根本不扫描列表并自动优化为无操作。

我尝试过godbolt.org检查生成的Core 和程序集。请注意,它仍然使用旧的 GHC 8.6.2。不过,我打开优化 ( -O2) 并编译

foo :: [Int] -> [Sum Int]
foo = fmap Sum
Run Code Online (Sandbox Code Playgroud)

并获得

foo = Example.foo1 `cast` (.....)
Example.foo1 = \ (v_a1iF :: [Int]) -> v_a1iF
Run Code Online (Sandbox Code Playgroud)

因此foo成为恒等函数,适当地强制,产生装配

   movq %r14,%rbx
   andq $-8,%rbx
   jmp *(%rbx)
Run Code Online (Sandbox Code Playgroud)

粗略地说,这应该相当于 GHC 运行时系统中的立即返回。

结论:Data.Coerce.coerce非常好,因为它确保了无操作,但即使是普通的 Haskell,经过优化,也能出奇地高效。