
Hello all! I have been experimenting with data and class declarations and came across a problem. I have been trying to do this: Code: data Fire = Burn | Ember data Water = Bubble | WaterGun class Elements a instance Elements Fire instance Elements Water data Elemental = Elemental { name :: String, move :: (Elements a) => a } So, the idea was that "move" in the data constructor "Elemental" would be able to take any value from either the type Fire or Water. However, the error message tells me this is an illegal polymorphic type. Therefore, I tried creating a function that could read my value for me after "show" was applied to the move. Hence, the data declaration for Elemental could now assign "move" to a String. The function looked like this: Code: getMove :: (Elements b) => String -> b getMove x = read x :: (Elements a) => a This will not work either, as the function "read" complains of ambiguity in the letter a. I also tried this (amongst other attempts) Code: getMove :: (Elements b) => String -> b getMove "Burn" = Burn getMove "Ember" = Ember getMove "Bubble" = Bubble getMove "WaterGun" = WaterGun getMove _ = error "Unknown move!" The above caused the function to infer the type Fire, and then complain about the type Water. So, how can I either create a function that can return multiple types like I am trying to above, or is there a way to adjust the data declaration for Elemental? Also, I have noticed that 3 :: (Num a) => a will work but Burn :: (Elements a) => a causes an ambiguity error. Why is this the case? Please help! Mike

I am sure others will give a better reply, but using RankNTypes you can
type-check the first alternative you mentioned. Depending on what you are
planning to do with the move field, it should be OK to use RankNTypes here,
I guess.
HTH,
Ozgur
On 20 August 2010 09:58, Michael Bradley
Hello all!
I have been experimenting with data and class declarations and came across a problem. I have been trying to do this:
Code:
data Fire = Burn | Ember data Water = Bubble | WaterGun
class Elements a
instance Elements Fire instance Elements Water
data Elemental = Elemental { name :: String, move :: (Elements a) => a }
So, the idea was that "move" in the data constructor "Elemental" would be able to take any value from either the type Fire or Water. However, the error message tells me this is an illegal polymorphic type.
Therefore, I tried creating a function that could read my value for me after "show" was applied to the move. Hence, the data declaration for Elemental could now assign "move" to a String. The function looked like this:
Code:
getMove :: (Elements b) => String -> b getMove x = read x :: (Elements a) => a
This will not work either, as the function "read" complains of ambiguity in the letter a. I also tried this (amongst other attempts)
Code:
getMove :: (Elements b) => String -> b getMove "Burn" = Burn getMove "Ember" = Ember getMove "Bubble" = Bubble getMove "WaterGun" = WaterGun getMove _ = error "Unknown move!"
The above caused the function to infer the type Fire, and then complain about the type Water. So, how can I either create a function that can return multiple types like I am trying to above, or is there a way to adjust the data declaration for Elemental?
Also, I have noticed that 3 :: (Num a) => a will work but Burn :: (Elements a) => a causes an ambiguity error. Why is this the case?
Please help!
Mike
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Not sure if this helps, but when you have
move :: Elements a => a
It doesn't mean move will return some unknown Elements type, it means you
can choose any type which is a member of elements and move will return that
type.
This means that
Burn :: Elements a => a
implies
Burn :: Water
Which is wrong.
3 :: Double
3 :: Integer
are both correct on the other hand.
/J
On 20 August 2010 10:58, Michael Bradley
Hello all!
I have been experimenting with data and class declarations and came across a problem. I have been trying to do this:
Code:
data Fire = Burn | Ember data Water = Bubble | WaterGun
class Elements a
instance Elements Fire instance Elements Water
data Elemental = Elemental { name :: String, move :: (Elements a) => a }
So, the idea was that "move" in the data constructor "Elemental" would be able to take any value from either the type Fire or Water. However, the error message tells me this is an illegal polymorphic type.
Therefore, I tried creating a function that could read my value for me after "show" was applied to the move. Hence, the data declaration for Elemental could now assign "move" to a String. The function looked like this:
Code:
getMove :: (Elements b) => String -> b getMove x = read x :: (Elements a) => a
This will not work either, as the function "read" complains of ambiguity in the letter a. I also tried this (amongst other attempts)
Code:
getMove :: (Elements b) => String -> b getMove "Burn" = Burn getMove "Ember" = Ember getMove "Bubble" = Bubble getMove "WaterGun" = WaterGun getMove _ = error "Unknown move!"
The above caused the function to infer the type Fire, and then complain about the type Water. So, how can I either create a function that can return multiple types like I am trying to above, or is there a way to adjust the data declaration for Elemental?
Also, I have noticed that 3 :: (Num a) => a will work but Burn :: (Elements a) => a causes an ambiguity error. Why is this the case?
Please help!
Mike
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Some others have suggested existential types, but that will not help here because the Elements class has no methods -- once you have wrapped up something in an existential Elements wrapper, there is literally nothing more you can do with it! I am not convinced that a type class is really what you want here. Type classes with no methods are rarely useful except for doing type-level programming. Why not just do something like this? data Element = Fire | Water data Item = Burn | Ember | Bubble | WaterGun elementOf :: Item -> Element elementOf Burn = Fire elementOf Ember = Fire ... etc data Elemental = Elemental { name :: String, move :: Item } -Brent On Fri, Aug 20, 2010 at 08:58:07AM +0000, Michael Bradley wrote:
Hello all!
I have been experimenting with data and class declarations and came across a problem. I have been trying to do this:
Code: data Fire = Burn | Ember data Water = Bubble | WaterGun
class Elements a
instance Elements Fire instance Elements Water
data Elemental = Elemental { name :: String, move :: (Elements a) => a } So, the idea was that "move" in the data constructor "Elemental" would be able to take any value from either the type Fire or Water. However, the error message tells me this is an illegal polymorphic type.
Therefore, I tried creating a function that could read my value for me after "show" was applied to the move. Hence, the data declaration for Elemental could now assign "move" to a String. The function looked like this:
Code: getMove :: (Elements b) => String -> b getMove x = read x :: (Elements a) => a This will not work either, as the function "read" complains of ambiguity in the letter a. I also tried this (amongst other attempts)
Code: getMove :: (Elements b) => String -> b getMove "Burn" = Burn getMove "Ember" = Ember getMove "Bubble" = Bubble getMove "WaterGun" = WaterGun getMove _ = error "Unknown move!" The above caused the function to infer the type Fire, and then complain about the type Water. So, how can I either create a function that can return multiple types like I am trying to above, or is there a way to adjust the data declaration for Elemental?
Also, I have noticed that 3 :: (Num a) => a will work but Burn :: (Elements a) => a causes an ambiguity error. Why is this the case?
Please help!
Mike
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Thank you for all you answers! I think I am going to try using polymorphic types within Elemental at first, and see if I can avoid trouble later. If that doesn't work, then I've got lots of alternatives! Thank you so much for your help! Mike
participants (4)
-
Brent Yorgey
-
Jonas Almström Duregård
-
Michael Bradley
-
Ozgur Akgun