2010-06-22 5 views
1

J'ai une erreur de type type ambigu sur la définition de "procès" ci-dessous, je me demande s'il y a quelque chose qui peut être fait pour que cette situation fonctionne? Je veux vraiment traiter uniquement des instances et non des types de données explicites (tels que MO1, MO2 inclus ci-dessous).En utilisant haskell read et typeclasses - type ambigu variable variable

module Tc102 where 

class (Show a, Read a) => MyObj a where 
    alpha :: a->String 
    beta :: a->Int 

data MO1 = MO1 { a1 :: String, b1 :: Int } deriving (Show,Read) 
data MO2 = MO2 { a2 :: String, b2 :: Int } deriving (Show,Read) 

instance MyObj MO1 where 
    alpha = a1 
    beta = b1 

instance MyObj MO2 where 
    alpha = a2 
    beta = b2 


a = MO1 "a" 3 
b = MO2 "b" 4 

test :: MyObj a => a->String 
test = alpha 


showMe :: (MyObj a)=> a -> String 
showMe = show 

readMe :: (MyObj a) => String -> a 
readMe = read 

trial :: MyObj a => a -> String 
trial = test . readMe . showMe 

merci d'avance tous! Je crains cependant que je pourrais avoir besoin d'aller à une fonction d'assistance qui convertirait ancienne ADT aux « dernières versions ...

Simon

EDIT Pour clarifier, imaginez que je suis montrer à un fichier, puis plus tard recharger l'objet. Ensuite, la fonction que j'ai est plus comme

trial :: String -> Int 
trial s = beta x 
    where x = readMe s 

Répondre

0

Vous ne pouvez pas lire le type de compilation à partir du fichier d'exécution. Vous devez explicitement implémenter la valeur variant avec le type à l'exécution.

A titre d'exemple:

data AnyMyObj = forall a . MyObj a => AnyMyObj a 

test :: AnyMyObj -> String 
test (AnyMyObj x) = alpha x 

showMe :: AnyMyObj -> String 
showMe (AnyMyObj x) = show x 

readMe :: String -> AnyMyObj 
readMe s = AnyMyObj (read s :: MO1) -- maybe something more complicated 

trial :: AnyMyObj -> String 
trial = test . readMe . showMe 
+0

Avec un peu plus de type-foo, il y a quelque chose qui devrait fonctionner. Merci! –

1

Vous obtenez l'erreur parce que le compilateur ne sait pas quel type de béton readMe devrait revenir, puisque tout ce qui est test exige que ce soit une instance de MyObj. Il pourrait être MO1, MO2, ou quelque chose d'autre entièrement, et readMe pourrait retourner un de ceux-ci. En supposant que vous voulez que readMe . showMe agisse comme id et sortez le même type que celui donné en entrée, le moyen le plus rapide est de définir une fonction qui fait exactement cela et de lui donner une signature de type qui équivaut à l'entrée et à la sortie types:

trial :: MyObj a => a -> String 
trial = test . readShowMe 
    where readShowMe :: MyObj a => a -> a 
      readShowMe = readMe . showMe 

maintenant, le compilateur peut déterminer à quel type concret pour donner à test en entrée.

+0

Ah, vous n'aimez pas juste quand les exemples vont mal, s'il vous plaît vérifier le poste original pour une clarification! :) Bien que je crois toujours que votre première partie de votre commentaire est toujours le problème.Il est dommage que vu l'information typeclass et le format de chaîne, que le runtime ne puisse pas déterminer l'obj est MO1 etc etc .... –

0

Il y a des trucs de fantaisie à cela, et la réponse ultime est en effet lire dans une sorte d'existentiel. Pour une exposition de fantaisie d'une manière très puissante/générale de faire ceci, voir les notes de conférence finales sans étiquette d'Oleg: http://okmij.org/ftp/tagless-final/course/#type-checking.

Mais c'est vraiment exagéré pour un exemple comme le vôtre - la supercherie entre généralement lorsque vous avez des structures arborescentes, et en particulier lorsque vous avez des structures arborescentes représentant des termes lambda.

Pour vos besoins, l'exemple d'ony ci-dessus est à peu près juste. Mais gardez à l'esprit que même si vous pouvez créer de nouvelles instances de MyObj, votre fonction de lecture ne pourra lire qu'un univers fixe, au moins sans hackery de haut niveau.

Il s'agit donc d'un cas où je voudrais savoir si vous voulez commencer par une classe de types, ou simplement plus de constructeurs dans un seul ADT.

data MyObj = MO1 { a1 :: String, b1 :: Int } 
      | MO2 { a2 :: String, b2 :: Int } deriving (Show,Read) 

... par exemple.

Questions connexes