2012-06-28 1 views
1

J'ai un problème avec Data.Serialize. Lorsque je code une structure de données, je peux encoder toutes les structures de données qui sont des instances de la classe Serialize. Cela fonctionne très bien. Je l'envoie ensuite sur le réseau.Quel est le bon usage de Data.Serialize "Sither String"

Cependant, j'ai un problème lors du décodage. La fonction de décodage me renvoie un type appelé "Either String" où je ne suis pas sûr de savoir comment utiliser cela pour reconstruire ma structure de données d'origine à partir du fait que le destinataire sait seulement qu'il avait précédemment été une instance de Serialize.

receiveMessage :: Socket -> IO (a, SockAddr) 
receiveMessage s = do 
     (msg, remoteSockAddr) <- recvFrom s 512 
     return (S.decode $ msg, remoteSockAddr) 

    Couldn't match type `a' with `Either String a0' 
     `a' is a rigid type variable bound by 
      the type signature for receiveMessage :: Socket -> IO (a, SockAddr) 
    In the expression: decode $ msg 
    In the first argument of `return', namely 
     `(decode $ msg, remoteSockAddr)' 
    In the expression: return (decode $ msg, remoteSockAddr) 

L'utilisation par ex. receiveMessage :: (Serialize a) => Socket -> IO (a, SockAddr) n'est pas une aide non plus. Comment pourrais-je gérer cela et mieux récupérer ma structure de données originale?

Répondre

8

Either est un type pour la gestion des erreurs. C'est comme Maybe, sauf que vous pouvez associer une valeur arbitraire (dans ce cas, certains String) avec le cas "erreur" correspondant à Nothing.

En d'autres termes, Either String a signifie que le résultat peut être String ou les données que vous souhaitez désérialiser.

Vous pouvez obtenir vos données sur le Either par correspondance de motif. Either a deux constructeurs: Left et Right. Dans ce cas, Left aura une chaîne et Right aura votre valeur. Donc, vous feriez quelque chose comme ceci:

case S.decode msg of 
    Left str -> ... -- handle your data not being deserialized correctly here 
    Right res -> ... -- res is your data 

De plus, vous devrez spécifier que le résultat est de type sérialisable. En ce moment, votre fonction receiveMessage promet de retourner type a; à la place, vous pouvez uniquement renvoyer un type de la classe Serialize. Donc, changez la signature de type à quelque chose comme Serialize a => Socket -> IO (a, SockAddr). Lorsque vous utiliserez réellement votre fonction, Haskell saura quel type est a et choisira le code de désérialisation approprié. HaskellHaskellHaskell Toutefois, puisque ce code existe uniquement pour les instances de la classe Serialize, vous devez spécifier cela dans la signature de type. Sur une note non liée: vous n'avez pas besoin de l'opérateur $ dans S.decode $ msg. Vous pouvez penser à l'opérateur en ajoutant les parenthèses entourant ce qui le suit, ainsi la ligne S.decode $ msg est équivalente à S.decode (msg), ce qui est inutile et pourrait être laissé comme S.decode msg.

+0

Merci, pensé que les parens dans ce cas sont autour (msg, remoteSockAddr), au moins il se comporte comme si .... –

+0

Ces parens sont différents et juste là pour faire un tuple. Le '$' ne s'étendrait que jusqu'à ',' dans ce cas, donc '(S.decode $ msg, remoteSockAddr)' est identique à '(S.decode (msg), remoteSockAddr)' qui est toujours redondant. –