如何在 Haskell 中使用未装箱的类型

How to operate with unboxed types in Haskell

对于 Int、Float 等,有未装箱的类型 GHC。 我知道基于它们构建的代码可以减少 运行 开销, 但我没有看到如何输入和输出数据的方法 to/from 一个基于未装箱 Int 的函数,即

GHC.Exts 定义函数 (+#) 和 (*#),但我找不到函数 boxing/unboxy

  readInt:: String -> Int#
  showInt:: Int# -> String

  boxInt :: Int# -> Int
  unboxInt :: Int -> Int#

实例 Show Int# 和实例 Read Int# 不能存在,因为 show 和 read 是多态的。

如果没有这些功能,我如何将未装箱类型的优化代码块与其余应用程序集成?

IntFloat 等只是 GHC 中的 data 类型:

data Int = I# Int#
data Float = F# Float#
-- etc.

构造函数仅由 GHC.Exts 导出。导入它并使用构造函数转换:

{-# LANGUAGE MagicHash #-}

import GHC.Exts

main = do I# x <- readLn
          I# y <- readLn
          print (I# (x +# y))

I know about code built on them is running with less overhead

虽然这在某种意义上是正确的,但您通常不必担心。 GHC 非常努力地优化内置类型的框,我希望它在大多数情况下都能做得很好,您也可以手动进行操作。

在实践中,您更应该注意的是确保

  • 它实际上看到了它知道未装箱形式的具体 IntFloat 类型。特别是,这 对多态函数起作用(多态性通常依赖于框,就像在 OO 语言中一样)。
    如果您希望一个函数是多态的并且使用原始类型仍然 运行 快速,请确保添加 SPECIALIZE 注释 and/or 重写规则。
  • 懒惰不会成为阻碍。未装箱的类型始终是严格的,因此严格性注释可以使 GHC 更容易删除箱子。

当然还有分析您的代码。

只有当你真的确定你想要它时(例如,确保当一个新的 GHC 以不同方式优化时,方框不会重新出现),或者如果如果您真的手动访问未装箱的原始类型,您想要获取 SIMD 指令。