Недавно меня застали врасплох, когда я попытался передать конструктор для типа типа * -> * -> *
с одним привязанным типом var функции, ожидающей конструктор для * -> *
. Конкретно, это было похоже на передачу (\x -> (x, 42)) :: (forall a. a -> (a, Int))
функции типа forall c. (forall a. a -> c a) -> ...
. Это двусмысленно, но не является ошибкой GHC: (,)
, приведенное к * -> *
, может быть интерпретировано как конструктор либо для левого, либо для правого аргумента, а GHC по умолчанию просто использует правый аргумент. Для совпадений более высокого типа будут использоваться наиболее правильные аргументы. Чтобы убедиться в этом, просто протестируйте предполагаемый тип:
foo :: c a b -> a -> b -> ()
foo _ _ _ = ()
bar = foo ((), 42, 'a') 42 'a' -- typechecks
Вместо этого я ошибочно полагал, что он будет соответствовать свободным переменным по порядку, но этот случай с более высоким рангом - единственный случай, когда это было бы явно предпочтительнее, а в других случаях это промывка. Есть ли официальная документация, описывающая это правило? Я немного раздражен, но также понимаю тот факт, что это не ошибка, потому что я могу предвидеть, что это экономит обертывание многих вещей в новые типы.
(a,b)
— это синтаксический сахар для(,) a b
, а(a,b,c)
— синтаксический сахар для(,,) a b c
и так далее. Дажеa -> b
— это сокращение от(->) a b
, а[a]
— это сахар для[] a
. Следовательно, все эти типы имеют формуT arg1 ... argn
для некоторого конструктора типовT
. - person chi   schedule 01.11.2019c
является частичным применением(,,)
к()
. - person chepner   schedule 01.11.2019