2014-10-02 63 views
16

我试图找出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相互递归,它也散落着hashs(#)。

在这两者之间,我无法弄清楚它是如何工作的。我知道这基本上只是mVar的一个伪构造函数,但模块的其余部分(实际上大部分库)都包含它们,并且我无法找到它们。谷歌搜索“哈斯克尔哈希”没有产生任何相关。

回答

18

他们是(字面上)魔法哈希值。他们区分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#) 

这其实是有点漂亮,当你想想看存根像这样,我们可以在运行时系统级统一处理懒惰IntChar

因为原语没有装箱,所以它们在类别层次上分开。这意味着,Int#没有那种*像正常的类型,这也意味着像

kindClash :: Int# -> Int# 
kindClash = id -- id expects boxed types 

不会编译。

为了进一步阐述你的代码,newMVar包括一个调用GHC中的编译器原语来分配一个新的可变变量。它不像编译器调用的简单包装那样相互递归。由于我们将IO视为不正常的状态monad,因此在这个函数的角落也会出现一些黑暗,但我们不要紧盯这个。我太喜欢我的理智了。

我不在日常代码中使用原语,也不应该。他们在实现疯狂优化的热点时,或者接近原始抽象时出现,比如你在看什么。

+0

谢谢。因此,为了理解库的片段,我基本上可以忽略它们,只是想想它们与之相关的类型? – Carcigenicate 2014-10-02 21:53:55

+1

@Carcigenicate很多,是的。 – bheklilr 2014-10-02 21:55:57

+0

@Carcigenicate我会这么说,如果你真的好奇,你可以阅读原始文档,但是我不认为你会从他们那里获得很多。 – jozefg 2014-10-02 21:56:27