Вероятно, проще сначала кратко изложить мою общую проблему, а затем показать, где я застрял.
Я хочу получить список JSON некоторого одноэлементного индексированного типа, где тип индексации также имеет связанное семейство типов. В коде:
data MyType = MyValue1 | MyValue2
type family MyFamily (mt :: MyType) where
MyFamily MyValue1 = Int
MyFamily MyValue2 = Double
data InputType (mt :: MyType) = InputNoFamily | InputWithFamily (MyFamily mt)
data OutputType (mt :: MyType) = OutputNoFamily | OutputWithFamily (MyFamily mt)
С помощью экзистенциальной квантификации я должен быть в состоянии скрыть переменный индекс и по-прежнему иметь возможность получать значения (с некоторой функцией типа с более высоким рейтингом, подобной продолжению - для этого может быть лучшее название). Я бы закончил с тем, что моя программа течет по линиям
JSON -> [Some InputType] -> [Some OutputType] -> JSON
где Some
из пакета exinst
, но также переопределен ниже. Я могу разобрать JSON в том случае, если я не разбираю MyFamily mt
, но я не могу придумать лучший способ включить его синтаксический анализ и из JSON.
То, что у меня есть до сих пор, ниже:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE RankNTypes #-}
module SO where
import Data.Aeson
import Data.Singletons.TH
import GHC.Generics
$(singletons [d|
data MyType
= MyValue1
| MyValue2
| MyValue3
deriving (Show, Eq, Generic)
|])
instance FromJSON MyType
type family MyFamily (mt :: MyType) :: * where
MyFamily 'MyValue1 = Double
MyFamily 'MyValue2 = Double
MyFamily 'MyValue3 = Int
-- stolen from exinst package
data Some (f :: k -> *) =
forall a. Some (Sing a) (f a)
some :: forall (f :: k -> *) a. SingI a => f a -> Some f
some = Some (sing :: Sing a)
withSome :: forall (f :: k -> *) (r :: *). Some f -> (forall a. SingI a => f a -> r) -> r
withSome (Some s x) g = withSingI s (g x)
data MyCompoundType (mt :: MyType)
= CompoundNoIndex
| CompoundWithIndex (MyFamily mt)
deriving instance (Show (SMyType mt), Show (MyFamily mt)) => Show (MyCompoundType mt)
-- instance with no parsing of `MyFamily`
instance
forall (mt :: MyType).
( SingKind (KindOf mt)
, FromJSON (DemoteRep (KindOf mt))
) => FromJSON (Some MyCompoundType) where
parseJSON = withObject "MyCompoundType" $ \o -> do
mt :: MyType <- o .: "myType"
case toSing mt of
SomeSing (smt :: SMyType mt') -> case smt of
SMyValue1 -> return $ some (CompoundNoIndex :: MyCompoundType mt')
SMyValue2 -> return $ some (CompoundNoIndex :: MyCompoundType mt')
SMyValue3 -> return $ some (CompoundNoIndex :: MyCompoundType mt')
Очевидно, мне нужно добавить ограничение FromJSON (MarketIndex mt)
, но мне также нужно иметь возможность привязать его к Some CompoundType
, для которого я создаю экземпляр.
Простое добавление константы FromJSON (MyFamily mt)
instance
forall (mt :: MyType).
( SingKind (KindOf mt)
, FromJSON (DemoteRep (KindOf mt))
, FromJSON (MyFamily mt)
) => FromJSON (Some MyCompoundType) where
parseJSON = undefined
выдает ошибки неоднозначного типа
Could not deduce (FromJSON (MyFamily mt0))
arising from the ambiguity check for an instance declaration
from the context (SingKind (KindOf mt),
FromJSON (DemoteRep (KindOf mt)),
FromJSON (MyFamily mt))
bound by an instance declaration:
(SingKind (KindOf mt), FromJSON (DemoteRep (KindOf mt)),
FromJSON (MyFamily mt)) =>
FromJSON (Some MyCompoundType)
at SO.hs:(57,3)-(61,39)
The type variable ‘mt0’ is ambiguous
In the ambiguity check for:
forall (mt :: MyType).
(SingKind (KindOf mt), FromJSON (DemoteRep (KindOf mt)),
FromJSON (MyFamily mt)) =>
FromJSON (Some MyCompoundType)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the instance declaration for ‘FromJSON (Some (MyCompoundType))’
Я вижу, что проверка типов, говорящая о mt0
, а не mt
, является большой проблемой, но я не знаю, как уговорить ее ожидать тип mt
в правой части ограничения.
(Я также понимаю, что не включил FromJSON (MyFamily mt)
экземпляров, но если средство проверки типов не может определить mt ~ mt0
, я не думаю, что в настоящее время это имеет значение).
Надеюсь, есть исправление?
Я потратил разумное количество времени, пробуя разные вещи, но происходит довольно много разных вещей (синглетоны, экзистенциалы и т. д.). Я медленно довожу себя до определенного уровня мастерства, но у меня просто недостаточно знаний или опыта, чтобы быть уверенным, как они (или нет) способствуют возникновению проблемы.