Я обнаружил, что могу сказать
{-# LANGUAGE RankNTypes #-}
f1 :: (forall b.b -> b) -> (forall c.c -> c)
f1 f = id f
(и HLint скажите, что я могу сделать "Eta уменьшить" здесь), но
f2 :: (forall b.b -> b) -> (forall c.c -> c)
f2 = id
не удалось скомпилировать:
Couldn't match expected type `c -> c'
with actual type `forall b. b -> b'
Expected type: (forall b. b -> b) -> c -> c
Actual type: (forall b. b -> b) -> forall b. b -> b
In the expression: id
In an equation for `f2': f2 = id
На самом деле у меня аналогичная проблема в более сложной ситуации, но это самый простой пример, о котором я могу думать. Таким образом, либо HLint не дает надлежащего указания здесь, либо компилятор должен обнаружить эту ситуацию, не так ли?
UPDATE
Другой вопрос о повторении выглядит аналогичным. Однако, хотя оба ответа весьма полезны, меня не удовлетворяют, поскольку они, похоже, не затрагивают суть вопроса.
Например, мне даже не разрешено назначать id
предлагаемым типом ранга 2:
f2 :: (forall b.b -> b) -> (forall c.c -> c)
f2 = id :: (forall b.b -> b) -> (forall c.c -> c)
Если проблема заключается только в типе, то явное обозначение типа должно решить его (идентификатор имеет тип a -> a
, и он был ограничен (forall b.b -> b) -> (forall c.c -> c)
. Поэтому, чтобы оправдать это использование, (forall b.b -> b)
должен соответствовать (forall c.c -> c)
> и это верно). Но приведенный выше пример показывает, что это не так. Таким образом, это истинное исключение из "eta reduce": вам нужно явно добавлять параметры для обеих сторон, чтобы преобразовать значение типизированного значения ранга 1 в значение с типом 2. 2.
Но почему существует такое ограничение? Почему компьютер не может автоматически унифицировать тип ранга 1 и тип 2-го ранга (забыть о типе вывода, все типы могут быть заданы с помощью обозначений)?