Как относиться к типу из внешнего контекста
Рассмотрим следующий фрагмент кода:
blah :: a -> b -> a
blah x y = ble x where
ble :: b -> b
ble x = x
Это компилируется под GHC, что по существу означает, что b
из третьей строки отличается от b
от первой строки.
Мой вопрос прост: существует ли способ как-то связать объявление типа ble
с типом, используемым во внешнем контексте, то есть объявлением типа blah
?
Очевидно, что это всего лишь пример, а не реальный случай использования для деклараций типов.
Ответы
Ответ 1
Это возможно с помощью расширения ScopedTypeVariables. Вам нужно использовать явный forall для переноса переменных типа в область.
blah :: forall a b. a -> b -> a
blah x y = ble x where
ble :: b -> b
ble x = x
Попытка загрузить это определение с включенным ScopedTypeVariables дает:
foo.hs:2:16:
Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for blah :: a -> b -> a at foo.hs:2:1
`b' is a rigid type variable bound by
the type signature for blah :: a -> b -> a at foo.hs:2:1
In the first argument of `ble', namely `x'
In the expression: ble x
In an equation for `blah':
blah x y
= ble x
where
ble :: b -> b
ble x = x
Вы можете сказать, что GHC интерпретирует два b
как один и тот же тип, потому что ошибка говорит о том, что a
и b
связаны в одной строке.
Ответ 2
Если вы не хотите использовать ScopedTypeVariables, вы можете использовать функцию хорошего ole fashion asTypeOf
.
-- defined in Prelude
asTypeOf :: a -> a -> a
x `asTypeOf` y = x
blah :: a -> b -> a
blah x y = ble x where
ble x = x `asTypeOf` y
Конечно, это не будет компилироваться из-за ошибки типа.
Обновление:
Я хотел бы указать, что иногда вам может быть немного хитроумно делать то, что вы хотите, с помощью asTypeOf
. Возьмем следующий пример, который суперплотно использует asTypeOf
, потому что я не хочу думать о случае, который действительно нуждается в asTypeOf
. Аналогичные решения будут работать одинаково для случаев реального мира.
foo :: Bounded a => Maybe a -> a
foo m = x
where
x = maxBound -- Q: how do I make (x :: a) when given (Maybe a)?
_ = Just x `asTypeof` m -- A: witchcraft!