Рассмотрим переменную, введенную в шаблон, например, f
в этом примере на Haskell:
case (\x -> x) of f -> (f True, f 'c')
Этот код приводит к ошибке типа («Не удалось сопоставить ожидаемый тип« Bool »с фактическим типом« Char »») из-за двух различных вариантов использования f
. Это показывает, что предполагаемый тип f
не является полиморфным в Haskell.
Но почему бы f
не быть полиморфным?
У меня есть две точки сравнения: OCaml и «учебник» Хиндли-Милнера. Оба предполагают, что f
должен быть полиморфным.
В OCaml аналогичный код не является ошибкой:
match (fun x -> x) with f -> (f true, f 'c')
Это оценивается как (true, 'c')
с типом bool * char
. Похоже, что OCaml прекрасно справляется с назначением f
полиморфного типа.
Мы можем обрести ясность, разобравшись с основами Хиндли-Милнера - лямбда-исчислением с «let», на которых основаны и Haskell, и OCaml. Конечно, применительно к этой базовой системе не существует такой вещи, как сопоставление с образцом. Мы можем провести параллели, хотя. Между «let» и «lambda» case expr1 of f -> expr2
гораздо ближе к let f = expr1 in expr2
, чем к (lambda f. expr2) expr1
. «Case», как и «let», синтаксически ограничивает привязку f
к expr1
, тогда как функция lambda f. expr2
не знает, к чему будет привязана f
, так как функция не имеет такого ограничения на то, где в программа это будет называться. Это было причиной того, что переменные с ограничением по буквам обобщаются в Хиндли-Милнера, а переменные с привязкой по лямбда - нет. Похоже, что те же самые рассуждения, которые позволяют обобщать переменные с привязкой, показывают, что переменные, введенные сопоставлением с образцом, могут быть обобщены.
Приведенные выше примеры минимальны для ясности, поэтому они показывают только тривиальный шаблон f
в сопоставлении с образцом, но все та же логика распространяется на произвольно сложные шаблоны, такие как Just (a:b:(x,y):_)
, которые могут вводить несколько переменных, которые все будут обобщенная.
Мой анализ верен? В частности, в Haskell - признавая, что это не просто Хиндли-Милнер и не OCaml - почему бы нам не обобщить тип f
в первом примере?
Было ли это явным языковым решением, и если да, то каковы были причины? (Я отмечаю, что некоторые в сообществе считают, что даже "let" не следует обобщать , но я бы предположил, что проектное решение предшествует этой статье.)
Если бы переменные, введенные в шаблон, были сделаны полиморфными, похожими на «let», разве это существенно нарушило бы совместимость с другими аспектами Haskell?