Что такое полиморфизм Льва

Как указывает название вопроса, я хочу знать, что такое полиморфизм Левита и какова его мотивация? Я знаю, что эта страница содержит некоторые детали, но большинство объяснений там перевернулось на мою голову.:)

Хотя эта страница немного дружелюбна, я все еще не могу понять мотивацию, стоящую за ней.

Ответ 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, а Ричард Э. (нынешний исполнитель этого) заявил, что для вики-страницы требуется обновление в текущем процессе.

Ссылки