4

I've been experimenting with deriving and had some hard time to understand how deriving (Read) works.

Let's have a look at the following data definition:

data Data         = D Int deriving (Eq, Read, Show)
data DataWithName = DWN { val :: Int } deriving (Eq, Read, Show)

Nothing special, just two data types each capsulating an Int, but the second one introduces a the name val for the Int.

In the interactive console, following instructions work as expected:

*Main> D 5
D 5
*Main> DWN 5
DWN {val = 5}
*Main> DWN { val = 5 }
DWN {val = 5}

while the following one is not working (EDIT: I expected this to not work)

*Main> D { val = 5 }

<interactive>:11:1:
    Constructor `D' does not have field `val'
    In the expression: D {val = 5}
    In an equation for `it': it = D {val = 5}

Now let's come down to it:

I thought that deriving Read would give me the same ways how to enter a data type, but in the following line 1 and line 2 work, while line 3 does not work because the parameter name is not given:

d1 = read "D 1" :: Data -- Works
d2 = read "DWN { value = 1 }" :: DataWithName -- Works
d3 = read "DWN 1" :: DataWithName -- This does not work because parameter is not given.

Is there some possibility to enable derving (Read) to also derive the "non-parameter-name constructor" such that read "DWN 5" :: DataWithName would work additionally to the "parameter-name constructor"?

Or can you provide me some information on how data reading / input should be handled?

Thanks!

Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
  • 3
    `Read` is pretty crummy in general. The biggest advantage of `Read` is that it's very widely implemented, and (pretty much?) all general-purpose parsing libraries can use its instances when they're available. But for any serious work, you should really use something like `parsec`, `attoparsec`, or (if performance is really critical and you're willing to deal with a parser generator) Happy. – dfeuer Jan 23 '16 at 17:57
  • Thanks, will keep that in mind. I just learned the basics of Haskell at university, yet I know nothing about developing _serious_ applications in Haskell. If you can provide me some _links / informations_ about _what to do / what to keep in mind_ when _reading / writing_ data, I would appriciate if you post another answer. My +1 you will receive ;) – Markus Weninger Jan 23 '16 at 18:04
  • 2
    That's a very general question. I wouldn't say I know much about "serious applications" either. `attoparsec` tends to be quite easy to use, but it doesn't have very good facilities for reporting parse errors. `parsec` is much more complicated and rather less intuitive IMO, but it has pretty good error handling. `trifecta` is known for excellent error handling, but also for lousy performance. – dfeuer Jan 23 '16 at 18:07
  • Okay, thanks for all the input! I think there is a long way to go until I get somewhere near productive using Haskell :D I think I have to find myself some real project which I then try to implement in Haskell. The proof of the pudding is in the eating. :P – Markus Weninger Jan 23 '16 at 18:10
  • 1
    This is a good starting point for learning more about parsers: https://github.com/JakeWheat/intro_to_parsing – Sibi Jan 23 '16 at 19:25

1 Answers1

2

I thought that deriving Read would give me the same ways how to enter a data type, but in the following line 1 and line 2 work, while line 3 does not work ...

That's not what Read does or deriving achieve. In fact the expression D { val = 5 } is not correct at all. val is just another normal function you get out from the record construction. You can even inspect its type:

ghci| > :t val
val :: DataWithName -> Int

The data constructor D only accepts Int as it's argument as evidenced by it's type:

ghci| > :t D
D :: Int -> Data

So no matter what you do, you cannot give it something like D { val = 5 } as it a type error.

Is there some possibility to enable deriving (Read) to also derive the "non-parameter-name constructor" such that read "DWN 5" :: DataWithName would work additionally to the "parameter-name constructor"?

No. But you can do some parsing of the String and convert it manually to the required data structure.

tom
  • 21,844
  • 6
  • 43
  • 36
Sibi
  • 47,472
  • 16
  • 95
  • 163
  • 1
    Thanks for the explaination, but I think there was some translation mistake by me. I _expected_ `D { val = 5 }` to not work. General it all was about if a have to convert the String manually, which you answered with *Yes, I have to do this* – Markus Weninger Jan 23 '16 at 16:33
  • " you can do some parsing of the String and convert it manually to the required data structure. " or `instance Read Data where read = unsafeCoerce . (read :: String -> DataWithName)` - if you like to live dangerously. – user2407038 Jan 23 '16 at 20:02
  • @user2407038 This gives me a compiler error in `7.10.3` as `read` is not actually a method of the `Read` typeclass: http://haddock.stackage.org/lts-4.2/base-4.8.2.0/Text-Read.html#g:1 – Sibi Jan 23 '16 at 20:28