Ответ 1
Они (буквально) магические хэши. Они различают примитивы GHC, такие как сложение, распакованные типы и распакованные кортежи. Вы можете включить их с помощью
{-# LANGUAGE MagicHash #-}
Теперь вы можете импортировать заглушки, которые позволяют использовать их с помощью
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
как извращенную монаду государства, но не будем пристально следить за этим. Мне очень нравится мое здравомыслие.
Я не использую примитивы в повседневном коде, и не должен. Они появляются при реализации сумасшедших оптимизированных горячих точек или почти примитивных абстракций, таких как то, что вы смотрите.