Типи як громадянин першого класу


10

Виходячи з фону C ++, я не розумію, для чого потрібні вирази типів / типів як громадянина першого класу? Єдиною моєю мовою, яка підтримує цю функцію, є Aldor.

Хтось має літературу про типи як громадянин першого класу чи знає деякі причини, чому це корисно?


3
У Ідріса є і такі.
ThreeFx

1
Ви запитуєте про загальне поняття "тип - це значення" (зване "відображення" або "метакласи" різними мовами) або про більш конкретне поняття виразів типу?
svick

1
@svick Мене цікавить останнє. На жаль, я не знайшов багато загальних речей щодо виразів типів, тож було б добре, якщо ви могли б запропонувати трохи літератури.
paul98

Відповіді:


11

Типи першого класу дозволяють щось називати залежним введенням тексту . Вони дозволяють програмісту використовувати значення типів на рівні типу. Наприклад, тип усіх пар цілих чисел є регулярним типом, тоді як пара всіх цілих чисел з лівим числом меншим, ніж праве число, є залежним типом. Стандартним вступним прикладом цього є кодовані по довжині списки (як правило, вони називаються Vectorв Haskell / Idris). Наступний псевдокод - це суміш Ідріса та Хаскелла.

-- a natural number
data Nat = Zero | Successor Nat

data Vector length typ where
  Empty : Vector Zero typ
  (::)   : typ -> Vector length typ -> Vector (Successor length) typ

Цей фрагмент коду говорить нам про дві речі:

  • Порожній список має нульову довжину.
  • consЯкщо елемент перейти до списку, створюється список довжини n + 1

Це дуже схоже на інше поняття з 0 n + 1, чи не так? Я повернусь до цього.

Що ми отримуємо від цього? Тепер ми можемо визначити додаткові властивості функцій, які ми використовуємо. Наприклад: Важливою властивістю appendє те, що довжина результуючого списку є сумою довжин двох списків аргументів:

plus : Nat -> Nat -> Nat
plus          Zero n = n
plus (Successor m) n = Successor (plus m n)

append : Vector n a -> Vector m a -> Vector (plus n m) a
append Empty  ys = ys
append (x::xs) ys = x :: append xs ys

Але в цілому ця техніка не здається всім корисною в повсякденному програмуванні. Як це стосується розеток, POST/ GETзапитів тощо?

Ну не виходить (принаймні, не без значних зусиль). Але це може допомогти нам іншими способами:

Залежні типи дозволяють сформулювати інваріанти в кодових правилах, як функція повинна вести себе. Використовуючи ці дані, ми отримуємо додаткову безпеку щодо поведінки коду, подібно до попередніх та післяумов Ейфелева. Це надзвичайно корисно для автоматизованого доведення теореми, що є одним із можливих застосувань Ідріса.

Повертаючись до наведеного вище прикладу, визначення списків, кодованих довжиною, нагадує математичне поняття індукції . В Idris ви можете фактично сформулювати поняття індукції в такому списку таким чином:

              -- If you can supply the following:
list_induction : (Property : Vector len typ -> Type) -> -- a property to show
                  (Property Empty) -> -- the base case
                  ((w : a) -> (v : Vector n a) ->
                      Property v -> Property (w :: v)) -> -- the inductive step
                  (u : Vector m b) -> -- an arbitrary vector
                  Property u -- the property holds for all vectors

Ця методика обмежується конструктивними доказами, але, тим не менш, є дуже потужною. Можна спробувати написати appendіндуктивно як вправу.

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

type_func : Vector n a -> Type
type_func Empty = Nat
type_func v     = Vector (Successor Zero) Nat

f : (v : Vector n a) -> type_func v
f Empty = 0
f vs    = length vs :: Empty

Це безглуздий приклад, але він демонструє те, що ви не можете наслідувати без типів першого класу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.