Подтвердить что ты не робот

Как относиться к типу из внешнего контекста

Рассмотрим следующий фрагмент кода:

blah :: a -> b -> a
blah x y = ble x where
    ble :: b -> b
    ble x = x

Это компилируется под GHC, что по существу означает, что b из третьей строки отличается от b от первой строки.

Мой вопрос прост: существует ли способ как-то связать объявление типа ble с типом, используемым во внешнем контексте, то есть объявлением типа blah?

Очевидно, что это всего лишь пример, а не реальный случай использования для деклараций типов.

4b9b3361

Ответ 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!