Я не эксперт по непредсказуемым типам, так что это одновременно потенциальный ответ и попытка узнать что-то из комментариев.
Нет смысла специализироваться
\/ a . a -> a (1)
до
(\/ a . a -> a) -> (\/ b . b -> b) (2)
и я не думаю, что непредсказуемые типы являются причиной, позволяющей это сделать.Квантификаторы приводят к тому, что типы, представленные левой и правой частью (2) неэквивалентных множеств в целом.Тем не менее, a -> a
в (1) подразумевает, что левая и правая стороны являются эквивалентными наборами.
Например, вы можете конкретизировать (2) в (int -> int) -> (string -> string).Но в любой системе, которую я знаю, это не тип, представленный (1).
Сообщение об ошибке выглядит так, как будто оно является результатом попытки устройства вывода типа Haskel объединить тип id
\/ a . a -> a
с типом, который вы указали
\/ c . (c -> c) -> \/ d . (d -> d)
Здесь я приведу количественные переменные для ясности.
Задача логического вывода типов состоит в том, чтобы найти наиболее общее назначение для a
, c
и d
, которое приводит к тому, что два выражения синтаксически равны.В конечном итоге он находит, что необходимо объединить c
и d
.Поскольку они по отдельности количественно определены, они зашли в тупик и вышли.
Возможно, вы задаете вопрос, потому что базовый логический тип - с надписью (c -> c) -> (d -> d)
- просто пашет вперед и устанавливает c == d
.Результирующий тип будет иметь вид
(c -> c) -> (c -> c)
, что является просто сокращением для
\/c . (c -> c) -> (c -> c)
Это, очевидно, является наименее наиболее общим выражением типа (теоретическая наименьшая верхняя граница) для типа x = x
где x
ограничено функцией с одним и тем же доменом и дополнительным доменом.
Тип "limitedId" в данном смысле в общем смысле является чрезмерно общим.Хотя это никогда не может привести к ошибке типа во время выполнения, существует много типов, описываемых выражением, которое вы ему дали - например, вышеупомянутый (int -> int) -> (string -> string)
- которые невозможно операционно, даже если ваш тип допустит их.