Що таке поліморфізм Левіті


81

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

Незважаючи на те, що ця сторінка дещо привітніша, я все ще не можу зрозуміти мотивацію, яка стоїть за нею.

Відповіді:


81

Примітка: Ця відповідь базується на останніх спостереженнях за дискусіями Левіті. Все, що стосується поліморфізму Левіті, наразі реалізоване лише у кандидатах на випуск GHC 8.0 і як таке може змінюватися (див., Наприклад, №11471 )


TL; DR : Це спосіб зробити функції поліморфними над піднятими та непіднятими типами, що неможливо за допомогою звичайних функцій. Наприклад, наступний код не вводить перевірку за допомогою регулярних поліморфізмів, оскільки Int#має kind #, але змінні типу у idмають kind *:

{-# 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

Зверніть увагу, що (->)все ще використовується деяка магія.


Перш ніж я почну відповідати на це питання, давайте зробимо крок назад і піти в один з найбільш часто використовуваних функцій, ($).

Що це ($)за тип? Ну, згідно з Хакежем та звітом, це так

($) :: (a -> b) -> a -> b

Однак це не на 100%. Це зручна маленька брехня. Проблема полягає в тому, що поліморфні типи (як aі b) мають вигляд *. Однак розробники (бібліотеки) хотіли використовувати ($)не лише для типів з видом *, але й для типів #, наприклад

unwrapInt :: Int -> Int#

Поки Intмає вид *(це може бути знизу), Int#має вид #(і не може бути знизу взагалі). Тим не менше, перевіряються такі типи коду:

unwrapInt $ 42

Це не повинно працювати. Пам'ятаєте тип повернення ($)? Це було поліморфно, і поліморфні типи мають вигляд *, ні #! То чому це спрацювало? Спочатку це була помилка , а потім - хакер (уривок листа Райана Скотта зі списку розсилки ghc-dev):

То чому це відбувається?

Довга відповідь полягає в тому, що до GHC 8.0, у підписі типу ($) :: (a -> b) -> a -> b, bнасправді було не в натуральній формі *, а навпаки OpenKind. OpenKind- це жахливий хак, який дозволяє заселяти як піднятий (вид *), так і непіднятий (вид #) тип, саме тому (unwrapInt $ 42) перевірки типу.

То що ж ($)нового типу в 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 .

Назва поліморфізм Левіті походить від того, що тепер ви можете писати поліморфні функції як для піднятого, так і для непіднятого типу, чогось, що було заборонено / можливо за попередніх обмежень поліморфізму. Це також позбавляє від OpenKindзлому одночасно. Це насправді "просто" про це, обробляючи обидва типи.

До речі, ви не самотні зі своїм запитанням. Навіть Саймон Пейтон Джонс сказав, що існує потреба у вікі-сторінці Левіті , а Річард Е. (поточний реалізатор цього) заявив, що вікі-сторінка потребує оновлення щодо поточного процесу.

Список літератури


3
"обробка обох видів" :)
Сібі,

4
Га Думаю, я віддав би перевагу потворному хаку, який приховував ці речі.
jberryman

3
Чому це не так ($) :: forall (w1 w2 :: Levity) (a :: TYPE w1) (b :: TYPE w2). (a -> b) -> a -> b, тобто чому ($)не слід використовувати з функціями з непіднятими аргументами?
Кактус

3
@Cactus, про який йдеться у "помилці", див. Коментар SPJ: ghc.haskell.org/trac/ghc/ticket/8739#comment:6
Зета,

1
@jberryman: # 11549 приховає RuntimeRep(замінює Levity).
Зета,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.