我试图找出mVars是如何工作的,我偶然发现了这段代码:
-- |Create an 'MVar' which is initially empty.
newEmptyMVar :: IO (MVar a)
newEmptyMVar = IO $ \ s# ->
case newMVar# s# of
(# s2#, svar# #) -> (# s2#, MVar svar# #)
除了与newMVar
混淆地相互递归之外,它还充满了哈希(#)。
在两者之间,我无法弄清楚它是如何工作的。我知道这基本上只是mVar的伪构造函数,但模块的其余部分(实际上大部分库)都包含它们,我找不到它们。谷歌搜索“Haskell哈希”并没有产生任何相关的东西。
答案 0 :(得分:19)
他们(字面上)魔法哈希。他们将GHC的原始特征与添加,未装箱类型和未装箱的元组区分开来。您可以使用
启用它们{-# LANGUAGE MagicHash #-}
现在您可以import存根,可以将它们与
一起使用import GHC.Exts
unboxed :: Int# -> Int# -> Int#
unboxed a# b# = a# +# b#
boxed :: Int -> Int -> Int
boxed (I# a#) (I# b#) = I# (unboxed a# b#)
当你想到它时,这实际上有点漂亮,通过包装像这样的神奇和严格的原语,我们可以在运行时系统级别统一处理惰性Int
和Char
。
因为原语不是盒装的,所以它们在种类层面上被隔离。这意味着Int#
没有类似普通类型*
的类型,这也意味着类似
kindClash :: Int# -> Int#
kindClash = id -- id expects boxed types
不会编译。
为了进一步详细说明您的代码,newMVar
包括调用GHC中的编译器原语来分配新的可变变量。与编译器调用的瘦包装器不同,它不是相互递归的。因为我们将IO
视为一个反常状态的monad,所以在这个函数的角落也会聚集一些黑暗,但是我们不要密切关注它。我非常喜欢我的理智。
我不会在日常代码中使用原语,也不应该使用原语。它们在实现疯狂优化热点时出现,或接近原始抽象,例如您正在查看的内容。