Ответ 1
Примечание:. Этот ответ основан на очень недавних замечаниях по обсуждениям в отношении Levity. Все, что касается полиморфизма Левита, в настоящее время реализовано только в кандидатах на выпуск GHC 8.0 и как таковое может быть изменено (например, # 11471).
TL; DR. Это способ сделать функции полиморфными над отмененными и непереходными типами, что невозможно при использовании обычных функций. Например, следующий код не вводит проверку с регулярным поли и shy; mor & shy; phi & shy; sms, так как Int#
имеет вид #
, но переменные типа в id
имеют вид *
:
{-# LANGUAGE MagicHash #-}
import GHC.Prim
example :: Int# -> Int#
example = id -- does not work, since id :: a -> a
Couldn't match kind ‘*’ with ‘#’
When matching types
a0 :: *
Int# :: #
Expected type: Int# -> Int#
Actual type: a0 -> a0
In the expression: id
Обратите внимание, что (->)
все еще использует некоторую магию.
Прежде чем я начну отвечать на этот вопрос, давайте сделаем шаг назад и перейдем к одной из наиболее часто используемых функций, ($)
.
Что такое ($)
? Ну, согласно Hackage и отчету, это
($) :: (a -> b) -> a -> b
Однако, это не 100% завершено. Это удобная ложь. Проблема в том, что полиморфные типы (например, a
и b
) имеют вид *
. Однако разработчики (библиотеки) хотели использовать ($)
не только для типов с добрым *
, но также и для типов #
, например
unwrapInt :: Int -> Int#
В то время как Int
имеет вид *
(он может быть снизу), Int#
имеет вид #
(и вообще не может быть внизу). Тем не менее, следующие коды typechecks:
unwrapInt $ 42
Это не должно работать. Помните тип возврата ($)
? Он был полиморфным, а полиморфные типы имеют вид *
, а не #
! Так почему это сработало? Во-первых, это была ошибка, а затем она была hack (выдержка из почты Райана Скотта в списке рассылки ghc-dev):
Так почему это происходит?
Длинным ответом является то, что до GHC 8.0 в сигнатуре типа
($) :: (a -> b) -> a -> b
,b
фактически не было натурой*
, а скорееOpenKind
.OpenKind
- это ужасный взлом, который позволяет подняться (вид*
) и (тип#
), чтобы обитать в нем, поэтому(unwrapInt $ 42)
typechecks.
Итак, что такое ($)
новый тип в GHC 8.0? Это
($) :: forall (w :: Levity) a (b :: TYPE w). (a -> b) -> a -> b
-- will likely change according to Richard E.
Чтобы понять это, мы должны посмотреть Levity
:
data Levity = Lifted | Unlifted
Теперь мы можем думать, что ($)
имеет либо один из следующих типов, так как существует только два варианта w
:
-- pseudo types
($) :: forall a (b :: TYPE Lifted). (a -> b) -> a -> b
($) :: forall a (b :: TYPE Unlifted). (a -> b) -> a -> b
TYPE
является магической константой и переопределяет виды *
и #
как
type * = TYPE Lifted
type # = TYPE Unlifted
Количественная оценка по типам также довольно новая и часть интеграции зависимых типов в Haskell.
Полиморфизм имени Levity исходит из того факта, что теперь вы можете писать полиморфные функции как с поднятыми, так и с неактивными типами, что не было разрешено/возможно с предыдущими ограничениями на поли и застенчивость, mor & shy; phism. Он также избавляется от взлома OpenKind
в одно и то же время. Это действительно "просто" об этом, обрабатывая оба вида видов.
Кстати, вы не одиноки с вашим вопросом. Даже Саймон Пейтон Джонс сказал, что существует необходимость в вики-странице Levity, а Ричард Э. (нынешний исполнитель этого) заявил, что для вики-страницы требуется обновление в текущем процессе.
Ссылки
- Политизм Левиты в зависимом Haskell; доклад Ричарда А. Айзенберга по ICFP 2015. Очень рекомендуется.
- Политизм Левита (расширенная версия) Ричарда Эйзенберга и Саймона Пейтона Джонса
-
GHC.Types
, часть библиотекиghc-prim
, поставляемая с GHC. - Обсуждение:
- Обсуждение ghc-dev.
- Обсуждение haskell-cafe.