Search code examples
haskellconstructorderiving

Deriving Read in Haskell: Why do I have to use the contructor's parameter names?


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!


Solution

  • 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.