Как относиться к типу из внешнего контекста - PullRequest
33 голосов
/ 06 декабря 2011

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

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

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

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

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

Ответы [ 2 ]

44 голосов
/ 06 декабря 2011

Это возможно с расширением ScopedTypeVariables . Вам нужно использовать явные поля, чтобы перевести переменные типа в область видимости.

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 связаны на одной строке.

16 голосов
/ 07 декабря 2011

Если вы не хотите использовать ScopedTypeVariables, вы можете использовать функцию good 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!
...