José Lopes | 17 Nov 15:59 2012
Picon

Parsing different types, same typeclass

Hello everyone,

I was wondering if you could help me!

So, I have a typeclass "Action" which defines method "run":

class Action a where
     run :: a -> Int

and two data types that are instances of this typeclass:

data A = A Int
         deriving (Read, Show)

instance Action A where
     run (A n) = n

data B = B Int
         deriving (Read, Show)

instance Action B where
     run (B n) = n

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
(Continue reading)

Stephen Tetley | 18 Nov 00:19 2012
Picon

Re: Parsing different types, same typeclass

Being concrete, all you can do is:

parseAction :: String -> Either A B
parseAction str
    | "(A " `isPrefixOf` str = Left $ read str
    | "(B " `isPrefixOf` str = Right $ read str

parseAction :: String -> Int
parseAction str
    | "(A " `isPrefixOf` str = run $ (read str :: A)
    | "(B " `isPrefixOf` str = run $ (read str :: B)

As you can't return a polymorphic /a/ when you have typed the cases to A or B.

Being less concrete, no doubt you can use existentials, but at this
point I'd recommend you re-evaluate what you are trying to do.
"José A. Lopes" | 18 Nov 01:32 2012
Picon

Re: Parsing different types, same typeclass

Hey Stephen,

Thank you for the reply!

Can you elaborate on how I can use existentials?
I always up for learning new (Haskell) stuff :)

Cheers,
José

On 18-11-2012 00:19, Stephen Tetley wrote:
> Being concrete, all you can do is:
>
> parseAction :: String -> Either A B
> parseAction str
>      | "(A " `isPrefixOf` str = Left $ read str
>      | "(B " `isPrefixOf` str = Right $ read str
>
>
> parseAction :: String -> Int
> parseAction str
>      | "(A " `isPrefixOf` str = run $ (read str :: A)
>      | "(B " `isPrefixOf` str = run $ (read str :: B)
>
> As you can't return a polymorphic /a/ when you have typed the cases to A or B.
>
> Being less concrete, no doubt you can use existentials, but at this
> point I'd recommend you re-evaluate what you are trying to do.

--

-- 
(Continue reading)

Stephen Tetley | 18 Nov 17:56 2012
Picon

Re: Parsing different types, same typeclass

With existentials an "extesible" version might look like this:

> {-# LANGUAGE ExistentialQuantification #-}
> {-# LANGUAGE ScopedTypeVariables #-}

... class Action and datatypes A and B the same as before ...

> -- some new ones...

> data C = C Int
>          deriving (Read, Show)

> instance Action C where
>      run (C n) = n

> data D = D Int
>          deriving (Read, Show)

> instance Action D where
>      run (D n) = n

The important one:

> data PolyA = forall a. Action a => PolyA a

> parseAction :: String -> PolyA
> parseAction str
>      | "(A " `isPrefixOf` str = PolyA $ (read :: String -> A) str
>      | "(B " `isPrefixOf` str = PolyA $ (read :: String -> B) str
>
(Continue reading)

Jose A. Lopes | 18 Nov 18:23 2012
Picon

Re: Parsing different types, same typeclass

Thanks Stephen. I will try this!

On 18-11-2012 17:56, Stephen Tetley wrote:
> With existentials an "extesible" version might look like this:
>
>> {-# LANGUAGE ExistentialQuantification #-}
>> {-# LANGUAGE ScopedTypeVariables #-}
>
> ... class Action and datatypes A and B the same as before ...
>
>
>> -- some new ones...
>> data C = C Int
>>           deriving (Read, Show)
>
>> instance Action C where
>>       run (C n) = n
>
>> data D = D Int
>>           deriving (Read, Show)
>> instance Action D where
>>       run (D n) = n
>
> The important one:
>
>> data PolyA = forall a. Action a => PolyA a
>
>> parseAction :: String -> PolyA
>> parseAction str
>>       | "(A " `isPrefixOf` str = PolyA $ (read :: String -> A) str
(Continue reading)

Jose A. Lopes | 18 Nov 18:34 2012
Picon

Re: Parsing different types, same typeclass

Thanks Stephen, that worked out just fine!

On 18-11-2012 18:23, Jose A. Lopes wrote:
> Thanks Stephen. I will try this!
>
> On 18-11-2012 17:56, Stephen Tetley wrote:
>> With existentials an "extesible" version might look like this:
>>
>>> {-# LANGUAGE ExistentialQuantification #-}
>>> {-# LANGUAGE ScopedTypeVariables #-}
>>
>> ... class Action and datatypes A and B the same as before ...
>>
>>
>>> -- some new ones...
>>> data C = C Int
>>>           deriving (Read, Show)
>>
>>> instance Action C where
>>>       run (C n) = n
>>
>>> data D = D Int
>>>           deriving (Read, Show)
>>> instance Action D where
>>>       run (D n) = n
>>
>> The important one:
>>
>>> data PolyA = forall a. Action a => PolyA a
>>
(Continue reading)

Chris Wong | 18 Nov 03:08 2012
Picon

Re: Parsing different types, same typeclass

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
(Continue reading)

Jose A. Lopes | 18 Nov 18:21 2012
Picon

Re: Parsing different types, same typeclass

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)
>>
(Continue reading)


Gmane