Я был возился с функцией runST
. Который имеет тип (forall s. ST s a) -> a
, и кажется, что пытаюсь использовать его любым способом, который не применяется непосредственно без какого-либо косвенного обращения, это довольно неприятно.Почему более ранние типы настолько хрупкие в Haskell
runST :: (forall s. ST s a) -> a
const :: a -> b -> a
так, подставляя a
в const
для forall s. ST s a
вы должны получить тип const runST
const runST :: b -> (forall s. ST s a) -> a
, но вместо этого GHC говорит, что не может сравниться с a
(forall s. ST s a) -> a
, но так как a
буквально означает forall a. a
что удовлетворенный каждым типом, я не вижу, что недействительно.
Как оказалось, используя \_ -> runST
вместо этого фактически работает просто отлично и дает правильный тип.
Как только у меня был constST
с правильным типом, я хотел посмотреть, могу ли я uncurry
его, но неудивительно, что тоже ломается. Но кажется, что это на самом деле не стоит, хотя по общему признанию, этот случай кажется менее очевидным, чем предыдущая:
constST :: b -> (forall s. ST s a) -> a
uncurry :: (a -> b -> c) -> (a, b) -> c
Так то, конечно, a
в uncurry
может быть заменен на b
в constST
и b
в uncurry
мог заменить на (forall s. ST s a)
на constST
, а a
в uncurry
может быть заменен на c
в constST
. Это дает нам:
uncurry constST :: (b, forall s. ST s a) -> a
Теперь, по общему признанию, этот тип является непроизводительным, который, как я знаю, довольно проблематичен. Но технически Just mempty
также является нецелесообразным при непосредственном подстановке без перемещения неявной forall
.
Just :: a -> Maybe a
mempty :: forall a. Monoid a => a
Just mempty :: Maybe (forall a. Monoid a => a)
Но forall
автоматически всплывали, чтобы дать вам:
Just mempty :: forall a. Monoid a => Maybe a
Теперь, если мы делаем то же самое для uncurry constST
мы должны получить разумный и, насколько я могу сказать, правильный тип:
uncurry constST :: (forall s. (b, ST s a)) -> a
Какой у вас высокий ранг, но не способствующий.
Может кто-нибудь объяснить мне, почему в принципе ни одно из вышеприведенных действий не работает с GHC 8, есть ли что-то более фундаментальное, что делает вышеупомянутое очень сложным в общем случае? Потому что, если нет, похоже, было бы очень приятно иметь вышеупомянутую работу, если бы только избавиться от раздражающего специального корпуса $
исключительно ради runST
.
На боковой ноте возможно, что вместо всех плавающих forall
мы могли бы иметь ImpredicativeTypes
, так как это нормально работает. Он правильно вводит тип для Just mempty
как Maybe (forall a. Monoid a => a)
, но похоже, что на самом деле это не так просто.Я слышал, что вывод непроизводительного типа на самом деле не выполним, но будет ли он каким-то образом ограничивать тип вывода предикативными типами, за исключением случаев, когда вы предоставляете сигнатуры типов, указывающие иначе. Аналогично тому, как MonoLocalBinds
делает локальные привязки мономорфными по умолчанию для вывода типа.
Я не знаю полной основы теории, но тип вывода с более политическими политиками более высокого ранга является сложным - IIRC, неразрешимым. Следовательно, полиморфизм должен быть каким-то образом ограничен, чтобы сделать вывод возможным. Типичным ограничением является разрешение каждой переменной типа 'forall a. ... ', который будет создан только с монотипами (включая' data, newtype's). Импрессивные типы ослабляют это ограничение, но сейчас они не работают нормально в GHC. – chi
@chi, мое смутное понимание состоит в том, что типы Haskell 98 + rank-2 могут быть выведены с трудом, но добавление более высоких рангов или расширение системного типа делает невозможным вывод. – dfeuer