новый тип с RankNTypes - PullRequest
       31

новый тип с RankNTypes

17 голосов
/ 20 марта 2012

Если я хочу объявить newtype таким образом, чтобы тип типа значения ограничивался наличием экземпляра для класса типов, кажется, что я могу сделать это с помощью:

{-# LANGUAGE RankNTypes #-}

newtype ShowBox = ShowBox (forall a. Show a => a)

GHCкомпилирует это просто отлично, но когда я пытаюсь и на самом деле использую ShowBox с

ShowBox "hello"

, я получаю ошибку компилятора

<interactive>:1:18:
    Could not deduce (a ~ [Char])
    from the context (Show a)
      bound by a type expected by the context: Show a => a
      at <interactive>:1:10-24
      `a' is a rigid type variable bound by
          a type expected by the context: Show a => a at <interactive>:1:10
    In the first argument of `ShowBox', namely `"hello"'
    In the expression: ShowBox "hello"
    In an equation for `a': a = ShowBox "hello"

Есть ли способ заставить это работать?

Ответы [ 2 ]

19 голосов
/ 20 марта 2012

Вы обещаете компилятору, что значение, которое вы поместите в ShowBox, будет иметь тип forall a. Show a => a.Есть только одно возможное значение с этим типом, и оно _|_.Я думаю, что вы, вероятно, хотите экзистенциальный тип, который выглядит довольно похожим, но означает что-то совсем другое.

{-# LANGUAGE ExistentialQuantification #-}

data ShowBox = forall a. Show a => ShowBox a

Это должно быть сделано с data, а не newtype.Сопоставление с образцом в конструкторе - это то, что в этом случае приводит экземпляр Show в область видимости.Поскольку newtype s не имеют представления во время выполнения, им негде хранить полиморфное свидетельство, которое подразумевает экзистенциальное количественное определение.

7 голосов
/ 20 марта 2012

Ваш конструктор Show имеет такой тип:

Show :: (forall a. Show a => a) -> ShowBox

Вы пытаетесь применить эту функцию к типу [Char], который не относится к типу forall a. Show a => a, потому что a - это «переменная Сколема», которая может быть объединена с другим типом только по очень строгим правилам (которые другие смогут объяснить лучше, чем я).

Вы уверены, что следующее не то, что вы хотите (по модулюdata против newtype)?Почему вы поместили forall внутри конструктора?

-- Show :: Show a => a -> ShowBox
data ShowBox = forall a. Show a => Show a
...