Алексей уже успел ответить на ваши вопросы.Вместо этого я поясню ваш пример с любыми подробностями, которые кажутся уместными.
class Tofu t where
tofu :: j a -> t a j
^^^ ^^^^^
^^^^^^^^^^^^
Подсвеченные биты должны иметь вид *
.Все, что находится по обе стороны от стрелки (уровня типа), должно иметь тип *
[1] , а сам термин стрелки (то есть весь термин j a -> t a j
) также имеет вид *
.Действительно, любой «тип» [2] , который может быть заселен значением, имеет вид *
.Если он имеет какой-либо другой вид, его значений не может быть (он просто используется для конструирования правильных типов в другом месте).
Таким образом, в сигнатуре tofu
выполняется следующее
j a :: *
t a j :: *
потому что они используются в качестве "обитаемых" типов, поскольку они являются аргументами (->)
.
И это единственные вещи, ограничивающие класс.В частности, a
может быть любого вида.С PolyKinds
[3]
a :: k -- for any kind k
j :: k -> *
t :: k -> (k -> *) -> *
^ ^^^^^^^^ ^
kind of a kind of j required since is used as inhabited type by ->
Итак, мы нашли требуемый вид t
.
Мы можем использовать аналогичные рассуждения для Frank
.
data Frank a b = Frank {frankField :: b a}
^^^^^^^^^ ^^^
Снова выделенные биты должны иметь вид *
, поскольку они могут иметь значения.В противном случае нет никаких ограничений.Обобщая, мы имеем
a :: k
b :: k -> *
Frank a b :: *
И, таким образом,
Frank :: k -> (k -> *) -> *
Мы можем видеть, что вид Frank
соответствует требуемому виду для Tofu
.Но это также имеет смысл для более конкретного вида, например:
data KatyPerry a b = KatyPerry a (b Int)
Попробуйте вывести ее вид и убедитесь, что он более конкретен, чем тип, требуемый для Tofu
.
[1] Это верно даже для стрелок на добром уровне, если мы примем TypeInType
.Без TypeInType
«виды» называются сортами , и никто не беспокоится о них;на этом уровне обычно ничего интересного не происходит.
[2] Я помещаю «тип» в кавычки, потому что технически только вещи с видом *
называются типами, а все остальное называется конструктором типа .Я пытался быть точным в этом, но я не мог найти неуклюжий способ ссылаться на оба сразу, и параграф стал очень грязным.Таким образом, «type» это.
[3] Без PolyKinds
, все с неограниченным видом, таким как k
, специализируется на *
.Это также означает, что тип Tofu
может зависеть от того, к какому типу вы впервые применили его экземпляр, или от того, создан ли экземпляр этого типа в том же модуле или в другом модуле.Это плохо.PolyKinds
это хорошо.