#haskell #higher-kinded-types #unification #higher-order-types
Вопрос:
Это, вероятно, глупый вопрос, но я не могу понять основные правила для следующего поведения:
foo :: t (f a) -> f a b -- accepted
foo = undefined
bar :: t [f a] -> f a b -- rejected
bar = undefined
Вполне логично, что f
применение к a
и a b
, соответственно, в bar
приводит к ошибке вида и, таким образом, отклоняется. Но почему это foo
принято?
Комментарии:
1.
t
может иметь вид(* -> *) -> *
, поэтому выполните сопоставление с конкретным типом. Для списка это невозможно, так как список имеет вид* -> *
, и это, таким образом, означает, чтоf a
он должен быть «конкретного» типа.2. Рассмотрим
data T container = T (container Int) (container String)
тип , который является параметрическим по сравнению с типами контейнеров и содержит контейнер сInt
s внутри и контейнер сString
s внутри, аtype F = (,)
также семейство контейнеров , по одному для каждого типа метаданных, которые помечают один содержащийся элемент некоторыми метаданными.3. Вам нужно уметь это делать, чтобы использовать трансформаторы монад, если вы слышали о них. Если нет, то в основном они преобразуют произвольную монаду в новую монаду, обладающую дополнительной функциональностью (один достаточно распространенный шаблон для построения сложного кода в Haskell состоит в том, чтобы укладывать несколько трансформаторов монад друг на друга). Для этого им нужно принять саму монаду в качестве параметра типа, а не применяемый монадический тип (например, им нужно принять
Maybe
,IO
,State s
и т. Д.; неMaybe Int
,IO String
, илиState s ()
).
Ответ №1:
Это что-то в этом роде f
.
Поскольку тип возвращаемого f a b
значения — т. е. f
применяется к двум параметрам, — это означает, что f :: Type -> Type -> Type
.
Но затем f a
используется в качестве элемента списка [f a]
— и элементы списка должны быть Type
, что означает это f a :: Type
, что означает это f :: Type -> Type
.
Несоответствие.
foo
работает, потому что типы могут быть частично применены. То есть, если f :: Type -> Type -> Type
, то f a :: Type -> Type
. И затем, типу t
разрешается иметь параметр вида Type -> Type
, так что все совпадает.
Чтобы повторить вышесказанное:
foo
работает, потому что типt
может иметь параметр видаType -> Type
.bar
не работает, потому что тип[]
(он же «список») должен иметь параметр видаType
.
Комментарии:
1. На уровне терминов вы не можете передать аргумент функции функции первого порядка. Тот же принцип применим и к уровню типов. Я ожидал, что это будет глупый вопрос. Все дело в видах:
foo :: t f -> t (->) -> f a b
с радостью принимается.