[Haskell-cafe] Parsing different types, same typeclass
Jose A. Lopes
jose.lopes at ist.utl.pt
Sun Nov 18 18:21:57 CET 2012
Hey Chris,
Thanks for you reply!
So the thing is: I actually had an algebraic data type Action with
several constructors, one for each Action. And I was deriving
Read so there was no problem there.
However, I want to be able to add and remove Actions more easily.
That is why I transformed the algebraic data type into a typeclass.
Similarly, if you think about Object Oriented programming, I want
the flexibility of subclassing, where new subclasses can be added
without a problem. The fact that parseAction only works on a finite
number of Actions is not problematic for now!
So, I would really appreciate your help in overcoming this problem!
Best regards,
José
On 18-11-2012 03:08, Chris Wong wrote:
> Hello José,
>
>> So, I have a typeclass "Action" which defines method "run":
>>
>> class Action a where
>> run :: a -> Int
>>
>> (snipped)
>>
>> Now, I want to parse either "A" or "B" from a String.
>> I was thinking about something like this...
>>
>> parseAction :: (Action a, Read a) => String -> a
>> parseAction str
>> | "(A " `isPrefixOf` str = (read :: String -> A) str
>> | "(B " `isPrefixOf` str = (read :: String -> B) str
>>
>> The problem is that when calling "parseAction" I get "ambiguous type
>> constraints". How to implement a parse function for two distinct
>> types that share the same typeclass "Action". Because after calling
>> "parseAction" I don't whether "A" or "B" was returned: I only care
>> that they are "Action" instances so I can call "run".
> The problem with your current type:
>
> (Action a, Read a) => String -> a
>
> is that it actually means:
>
> For any type that implements Action and Read, I can convert a
> string to that type.
>
> This is wrong because if a user of your module added another type C,
> your function wouldn't be able to handle it -- it only "knows" about A
> and B. That is what GHC is trying to tell you.
>
> How you can solve this problem depends on what you're trying to do. If
> there is a finite number of actions, you can merge them into a single
> type and remove the type class altogether:
>
> data Action = A Int | B Int
> deriving (Read, Show)
>
> run :: Action -> Int
> run (A x) = x
> run (B x) = x
>
> parse :: String -> Action
> parse = read
>
> If you have a possibly unlimited number of possible actions, there are
> many approaches to this -- including, as Stephen said, existential
> types. However, it's hard to decide on a proper solution without
> knowing what you're actually trying to do.
>
> Chris
>
>> Best regards,
>> José
>>
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
--
José António Branquinho de Oliveira Lopes
Instituto Superior Técnico
Technical University of Lisbon
More information about the Haskell-Cafe
mailing list