Сначала несколько замечаний:
- Не указывайте такой экземпляр . Этот экземпляр будет соответствовать любому формату
f
, независимо от тогоf
, действительно ли он вWrapper
классе. В частности, это также противоречило бы со стандартными экземплярами, такими какFromJSON (Vector a)
, даже еслиVector
это не может быть (хороший) экземплярWrapper
. Причиной этого является то, что система классов Haskell основана на предположении открытого мира : компилятор никогда не может предположить, что тип не находится в каком-то классе, потому что любой мог, по крайней мере технически говоря, добавить экземпляр позже. -
Я бы советовал не использовать
Proxy
в новом коде. Я всегда считалProxy
уродливый хак, едва менее уродливым, чемundefined :: T
аргументы, которые обычно использовались для этого в старом кодеке Haskell. В новом GHC, то проблема была решена должным образом-XAllowAmbiguousTypes
с-XTypeApplications
; они позволяют просто сделать подпись{-# LANGUAGE AllowAmbiguousTypes #-} class Wrapper f where ... name :: String
а затем вместо
name (Proxy :: Proxy (f a))
записиname @f
.
Теперь к реальной проблеме: ваш код не работает, потому что переменные типа в стандартном Haskell всегда принадлежат только контексту подписи / класса одного типа, но не могут использоваться в коде, который его определяет. IOW, переменные типа не используют те же области имен , что и переменные значения, поэтому, когда вы упоминаете Proxy (f a)
компилятор a € ?disambiguatesa €? переменные типа to f0
и a0
. Это немного глупый недостаток Haskell98, и он адресован -XScopedTypeVariables
расширением (вместе с ключевым словом ?
aka forall
). Следующее будет компилироваться само по себе:
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax #-}
instance ? f a . (IsString a, FromJSON a, Wrapper f) => FromJSON (f a) where
parseJSON (String s) = wrap <$> pure (fromString $ unpack s)
parseJSON invalid = typeMismatch (name (Proxy :: Proxy (f a))) invalid
Как я уже сказал, такой пример не должен определяться. Я думаю, что вы действительно хотите что-то вроде
{-# LANGUAGE DataKinds, KindSignatures, TypeApplications #-}
import GHC.TypeLits (Symbol, KnownSymbol, symbolVal)
data Wrapper (n :: String) (a :: *)
= Wrapper a
| TypeMismatch String
instance ? a s . (IsString a, FromJSON a, KnownSymbol s)
=> FromJSON (Wrapper s a) where
parseJSON (String s) = Wrapper <$> pure (fromString $ unpack s)
parseJSON invalid = TypeMismatch $ symbolVal @s Proxy
Никаких занятий не требуется.