Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instance of Read class in Haskell

I was just starting having fun with haskell when I got stuck.

I'm trying to make my new data type (let's call it MyType) instance of the Read class. Mytype is a type constructor, so it takes another type as parameter. I wanted to write this kind of code

    instance (Read a) => Read (MyType a) where
        readsPrec _ r = [foo (read r :: a ), r]

but it gives me the following error

Could not deduce (Read a2) arising from a use of `read' from the context (Read a).

I thought that since a is Readable I could just infer it, but apparently I'm wrong. Any ideas?

EDIT: I have changed the previous code to

readsPrec _ r = [foo (read r :: a ), ""]

so if I type: read "myString" :: MyType a it works perfectly fine. Now I was hoping that if I would use read "myString" within a context, I shouldn't have to specify the type to read. But the problem is that with

bar (read myString) a

where bar:: MyType a -> a -> MyType a, I got Ambiguos variable type.

Is it possible to do something like that without getting that kind of error?

I hope it's clearer now, I'm trying to simplify the code but I hope I didn't omit anything crucial.

like image 778
user1544128 Avatar asked Jan 19 '26 12:01

user1544128


1 Answers

The code actually typechecks if written as

instance (Read a) => Read (MyType a) where
        readsPrec _ r = [(foo (read r),r)]

if foo has type a -> MyType a. The compiler can figure out from the expected type signature of readsPrec that the call to foo ought to return a MyType a, and hence (by the type of foo), the expression read r ought to have type a.

But why does it fail when you annotate that with :: a? Because type variables are local to the type signature they appear in. So the a there is totally unrelated to the a in the instance heade and with read r :: a you are actually saying: The expression read r can have any arbitrary type. But an arbitrary type has no Read instance, hence the error message. In the message, the compiler renamed the inner a to a2 to avoid a name clash.

Your code can work as expected, though, if you add {-# LANGUAGE ScopedTypeVariables #-} to the module header. Now, the a in read r :: a refers to the type of a in the instance header and all goes well.

Note that you are not using readsPrec correctly, but I guess that is not part of the question.

like image 189
Joachim Breitner Avatar answered Jan 21 '26 03:01

Joachim Breitner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!