Newtype с RankNTypes - программирование
Подтвердить что ты не робот

Newtype с RankNTypes

Если я хочу объявить 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"

Есть ли способ сделать эту работу?

4b9b3361

Ответ 1

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

{-# LANGUAGE ExistentialQuantification #-}

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

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

Ответ 2

Ну, ваш конструктор Show имеет этот тип:

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

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

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

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