2017-08-10 4 views
1

Der folgende Code nicht kompiliert werden und gibt den FehlerWie validiere ich die type family nach dem Speichern in json?

kann mit ‚c‘ Typ ‚c1‘ entspricht ‚c1‘ nicht eine starre Variable vom Typ von ein Muster mit Konstruktor gebunden: SomeReq :: forall c. Conn c => Req c -> SomeReq, in einer Gleichung für ‚run‘

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE ExistentialQuantification #-} 

module Main where 

import qualified Data.Text as T 

class Conn c where 
    data Auth c :: * 
    data Env c :: * 
    data Req c :: * 

    getEnv :: Auth c -> IO (Env c) 
    runReq :: Env c -> Req c -> IO String 

data SomeAuth = forall c. (Conn c) => SomeAuth (Auth c) 
data SomeReq = forall c. (Conn c) => SomeReq (Auth c) 

run :: SomeAuth -> SomeReq -> IO String 
run (SomeAuth auth) (SomeReq req) = do 
    env <- getEnv auth 
    runReq env req 

main :: IO() 
main = return() 

Der Grund für die Existenziale ist, dass ich diese Datentypen in json speichern müssen. (Auth c) und (Req c) werden immer separat gespeichert, aber immer zusammen verwendet.

Ich gehe davon aus, dass der einzige mögliche Weg, dies zu machen, eine Art Laufzeitprüfung ist, um zu überprüfen, ob diese Typen übereinstimmen. Ich bin mir nicht sicher, wie ich das machen soll.

+0

Sie sagen, dass Ihr JSON-Speicher bestimmt, was "c" ist? Oder wird "c" durch die statische Struktur des Codes bestimmt? –

+0

'c' ist ein Service, auf dem wir die Anfrage ausführen können. Zum Beispiel S3 oder Google – whitehead1415

Antwort

2

Mit SomeAuth und SomeReq haben Sie keine Möglichkeit herauszufinden, ob die Typen, die sie umhüllen, gleich sind. Wenn es endlich viele Möglichkeiten (eine endliche „Universum“) sind, dann können Sie eine GADT verwenden sie markieren:

data CTag c where 
    C1T :: CTag C1 
    C2T :: CTag C2 
    ... 

eine passende CTag in SomeAuth und ein in SomeReq und Muster kleben.

Wenn c irgendeine alte Sache sein könnte, ist Ihre beste Wette Data.Typeable zu verwenden, eine Typeable Beschränkung auf die SomeAuth und SomeReq Konstrukteuren hinzufügen. Sobald Sie beide geöffnet haben, können Sie herausfinden, ob die Typen übereinstimmen, und wenn dies der Fall ist, sollten Sie Beweise dafür finden.

+0

Danke für diese einfache Lösung. Ist es möglich, eine generische Funktion zu haben, die SomeAuth konstruiert? Etwas wie 'mkSomeAuth :: Auth c -> SomeAuth' – whitehead1415

+0

Um genauer zu sein gehe ich mit dem Hinzufügen von CTags in SomeAuth, also denke ich die Frage ist, wie man von' (Auth c) gehen -> CTag c' – whitehead1415

+0

ging ich zurück herumzuspielen und "Typable" als Einschränkung hinzuzufügen und ich bin ein bisschen verloren. Können Sie auf ein Beispiel zeigen? – whitehead1415