[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