Короткий ответ - вывод типа не всегда работает с типами более высокого ранга.В этом случае он не может определить тип (.)
, но он проверяет, добавляем ли мы явную аннотацию типа:
> :m + Control.Monad.ST
> :set -XRankNTypes
> :t (((.) :: ((forall s0. ST s0 a) -> a) -> (a -> forall s1. ST s1 a) -> a -> a) runST return) $ True
(((.) :: ((forall s0. ST s0 a) -> a) -> (a -> forall s1. ST s1 a) -> a -> a) runST return) $ True :: Bool
Та же проблема возникает и в первом примере, если мы заменим($)
с нашей собственной версией:
> let app f x = f x
> :t runST `app` (return `app` True)
<interactive>:1:14:
Couldn't match expected type `forall s. ST s t0'
with actual type `m0 t10'
Expected type: t10 -> forall s. ST s t0
Actual type: t10 -> m0 t10
In the first argument of `app', namely `return'
In the second argument of `app', namely `(return `app` True)'
Опять же, это можно решить, добавив аннотации типов:
> :t (app :: ((forall s0. ST s0 a) -> a) -> (forall s1. ST s1 a) -> a) runST (return `app` True)
(app :: ((forall s0. ST s0 a) -> a) -> (forall s1. ST s1 a) -> a) runST (return `app` True) :: Bool
В данном случае существует специальное правило ввода вGHC 7, который применяется только к стандартному оператору ($)
.Саймон Пейтон-Джонс объясняет это поведение в ответе в списке рассылки пользователей GHC :
Это мотивирующий пример для вывода типов, который может иметь дело с непредсказуемыми типами.Рассмотрим тип ($)
:
($) :: forall p q. (p -> q) -> p -> q
В примере нам нужно создать экземпляр p
с помощью (forall s. ST s a)
, и это то, что означает непредсказуемый полиморфизм: создание переменной типа с полиморфным типом.
К сожалению, я не знаю ни одной системы разумной сложности, которая могла бы проверять [это] без посторонней помощи.Существует множество сложных систем, и я был соавтором по крайней мере двух работ, но все они слишком сложны, чтобы жить в GHC.У нас была реализация коробочных типов, но я снял ее при реализации нового средства проверки типов.Никто не понимал этого.
Однако люди так часто пишут
runST $ do ...
, что в GHC 7 я реализовал специальное правило ввода, только для инфиксного использования ($)
.Просто представьте, что (f $ x)
- это новая синтаксическая форма с очевидным правилом набора текста, и все в порядке.
Ваш второй пример не удался, поскольку для (.)
.
такого правила не существует.