Когда вы сопоставляете шаблон All prf
со значением типа All phi
, prf
извлекается как сущность полиморфа c типа forall a. phi a
. В этом случае вы получите no :: forall a. NotPred phi a
. Однако вы не можете выполнить сопоставление с образцом для объекта этого типа. В конце концов, это функция от типов к значениям. Вам нужно применить его к указанному типу c (назовите его _a
), и вы получите no @_a :: NotPred phi _a
, который теперь можно сопоставить для извлечения f :: phi _a -> Void
. Если вы расширите свое определение ...
{-# LANGUAGE ScopedTypeVariables #-}
-- type signature with forall needed to bind the variable phi
theorem :: forall phi. All (NotPred phi) -> Not (Ex phi)
theorem prf wit = case prf of
All no -> case no @_a of -- no :: forall a. NotPred phi a
NP f -> case wit of -- f :: phi _a -> Void
Ex (x :: phi b) -> f x -- matching against Ex extracts a type variable, call it b, and then x :: phi b
Итак, вопрос в том, какой тип следует использовать для _a
? Итак, мы применяем f :: phi _a -> Void
к x :: b
(где b
- переменная типа, хранящаяся в wit
), поэтому мы должны установить _a := b
. Но это грубое нарушение. b
извлекается только путем сопоставления с Ex
, что происходит после того, как мы специализировали no
и извлекли f
, поэтому тип f
не может зависеть от b
. Таким образом, не существует выбора _a
, который может заставить эту работу работать, не позволяя экзистенциальной переменной покинуть ее область действия. Ошибка.
Решение, как вы обнаружили, состоит в том, чтобы сопоставить с Ex
(таким образом извлекая тип из него) перед применением этого типа к no
.
theorem :: forall phi. All (NotPred phi) -> Not (Ex phi)
theorem prf wit = case wit of
Ex (x :: phi b) -> case prf of
All no -> case no @b of
NP f -> f x
-- or
theorem :: forall phi. All (NotPred phi) -> Not (Ex phi)
theorem (All no) (Ex x) | NP f <- no = f x