Чи стираються типи в Haskell?


13

Хаскелл має поняття "загальних функцій", яке має певну схожість із загальним лісом - не маючи ні досвіду роботи з Хаскеллом, ні загальним лісом, я можу бути тут дуже приблизним. Це означає, що можна визначити загальний to_stringінструмент для визначення рядкового подання для всіх типів. Звичайно, об'єкт повинен бути визначений в особливих випадках, але є to_stringфункція, підпис якої є α → string.

Чи стираються типи в Haskell, як вони є в OCaml? Якщо так, то як реалізація "загальних функцій" у Haskell відрізняється від звичайної lisp, де типи є динамічними і, таким чином, не стираються?

Я розумію, що відомості про реалізацію конкретні для компілятора, але, мабуть, є положення, спільні для багатьох або всіх реалізацій.


5
Пам'ятайте, що ви, мабуть, не можете визначити нетривіальну функцію типу a -> String. Ви, швидше за все, матимете обмеження типу, наприклад Show a => a -> String.
DJG

Відповіді:


16

Поки що відповідь є хибною.

Потрібно розрізняти "параметричний" та "спеціальний перевантаження" поліморфізм. Параметричні засоби "поводяться однаково для всіх типів a", тоді як "ad hoc" - те, що Саймон називає поліморфним - змінює реалізацію на основі типу.

Приклади обох є reverse :: [a] -> [a], що є параметричним, а show :: Show a => a -> Stringяке "тимчасовим" перевантаженим.

Якщо ви хочете більше абстрактної інтуїції, я думаю, що це допомагає розглянути класи дієслів на природній мові, які "працюють" для всіх об'єктів, як "володіти" або "думати про", які не обмежують об'єкт, але " відкривати "вимагає того, що ми можемо говорити, можна відкрити. Я можу "думати про двері" і "відчиняти двері", хоча немає сенсу, наприклад, "відкрити дерево". Ще більше взяти приклад "відкрити" - це "спеціальна поліморфність" як "відкрити вікно" і "відкрити скаргу-квиток із обслуговування клієнтів" - це дві дуже різні речі. Якщо це здається вимушеним - забудьте це! Це працює для мене.

Обидва вони вирішені під час компіляції, проте фактично "стерті". Модульні різні розширення GHC і Template Haskell і т.д. Типи будуть фактично стерті під час компіляції і ніколи не перевіряються на час виконання.

Параметрично поліморфні функції поводяться однаково для всіх типів, тому потрібно генерувати лише один фрагмент коду, тоді як компілятор вирішує під час компіляції, яку версію функції "класового типу" потрібно запускати у певній програмі. Тому також існує обмеження на один екземпляр на тип на тип класу та відповідну обробку "нового типу".

Реалізація детально описана в підручнику SPJs та Wadler та Blotts на типових класах .


Як ви вважаєте, я повинен видалити свою відповідь?
Саймон Берго

Ні, це добре, якщо ви попередили, що не потрапляєте в точну лексику
:)

Чи можете ви трохи розширити питання, чому GHC може стерти типи? Це завдяки основним набору тексту?
Саймон Бергот

2
Як правило, під час виконання або параметрично поліморфні функції можуть існувати лише один раз і викликати спеціальні поліморфні функції за допомогою якогось віртуального методу диспетчеризації, або весь код може бути сформований для кожного типу окремо і виклики статично пов'язані. Будь-яка реалізація є правильною з мовної точки зору (зауважте, що Haskell не має поліморфних типів; така річ може бути створена лише з forallрозширенням GHC ).
Ян Худек

Чи є розширення GHC, які не дозволяють видалити типи? Перевантаження статична і без повних залежних типів я нічого не можу придумати
Daniel Gratzer

1

попередження: мій досвід роботи в CS не дуже сильний, тому я не завжди можу використовувати правильну лексику, і я можу помилитися в деяких моментах. У всякому разі, ось моє розуміння:

Я думаю, що ви плутаєте дженерики з поліморфізмом.

Загальні типи, такі як List<Foo>, використовуються для опису типів, які приймають інші типи як параметр, і дозволяють перевірити більш багатий тип.

Загальна функція у haskell може бути count:: List a -> Int. Він приймає списки будь-якого типу та повертає кількість елементів. Є лише одна реалізація.

Зазвичай, визначаючи Список, ви нічого не можете припустити про Т. Ви можете лише зберігати його і повертати.

Ваша to_stringфункція - це поліморфна функція, це означає, що вона буде вести себе по-різному за різних обставин. У haskell це робиться з typeclasses, який працює як прикметники для типів.

У вас є Showтип класу, який визначає show :: a -> Stringфункцію.

Коли тип Fooреалізує Showклас класу, він повинен надати визначення show. Цей тип може бути використаний у функціях, що вимагають Showкваліфікатора (як у Show a => a -> whatever). Haskell не може стерти типи, оскільки ці функції повинні знайти правильну реалізацію showфункції.


Поширені поліморфні функції називаються "загальними функціями" IIRC, і я використовував ту саму (заплутану) лексику. Ваша відповідь корисна, а ваш остаточний аргумент досить переконливий. .-)
user40989

"Є лише одна реалізація" - тільки одна, яка має сенс, впевнено, але існує нескінченно багато можливих. Функція типу a → b має | b | ^ | a | можливі реалізації (врахуйте кількість функцій типу Bool → Bool), а списки не мають верхнього обмеження розміру.
Джон Перді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.