Мне нужна коллекция чисел, и я должен иметь возможность легко вставить ее в середину списка, поэтому я решил создать связанный список.Будучи опытным программистом на Hask (Hask-- являясь вариантом Haskell, который не имеет универсального количественного определения!), Я быстро без проблем набираю функцию типа и длины:
data IntLinkedList = IntNil | IntCons Int IntLinkedList
length_IntLinkedList :: IntLinkedList -> Int
length_IntLinkedList IntNil = 0
length_IntLinkedList (IntCons _ tail) = 1 + length_IntLinkedList tail
Позже я понимаю,было бы удобно иметь вариантный тип, который может хранить числа, не такие большие, как 1, и не такие маленькие, как 0. Нет проблем ...
data FloatLinkedList = FloatNil | FloatCons Float FloatLinkedList
length_FloatLinkedList :: FloatLinkedList -> Int
length_FloatLinkedList FloatNil = 0
length_FloatLinkedList (FloatCons _ tail) = 1 + length_FloatLinkedList tail
Boy этот кодвыглядит ужасно знакомым!И если позже я обнаружу, что было бы неплохо иметь вариант, который может хранить String
s, я снова оставляю копирование и вставку точно такого же кода и настройку точно таких же мест, которые являются специфическими для содержимого типа.Разве не было бы неплохо, если бы был способ раз и навсегда создать связанный список, который мог бы содержать элементы любого отдельного типа, и функцию длины, которая работала бы равномерно, независимо от того, какие элементы у нее были?В конце концов, наши функции длины даже не заботились о значениях элементов.В Haskell это именно то, что дает вам универсальное количественное определение: способ написать единственную функцию, которая работает со всей коллекцией типов.
Вот как это выглядит:
data LinkedList a = Nil | Cons a (LinkedList a)
length_LinkedList :: forall a. LinkedList a -> Int
length_LinkedList Nil = 0
length_LinkedList (Cons _ tail) = 1 + length_LinkedList tail
The forall
говорит, что эта функция для всех вариантов связанных списков - связанных списков Int
s, связанных списков Float
s, связанных списков String
s, связанных списков функций, которые принимают FibbledyGibbets и возвращают связанные спискикортежи Grazbars и WonkyNobbers, ...
Как мило!Теперь вместо отдельных типов IntLinkedList
и FloatLinkedList
мы можем просто использовать LinkedList Int
и LinkedList Float
для этого, а length_LinkedList
, реализованный один раз, работает для обоих.