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"
Есть ли способ сделать эту работу?
Ответы
Ответ 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