oldboy123
oldboy123

Reputation: 61

Types and Typeclasses in Haskell: Missing field in record construction

I have three datatypes:

data Person = Person { firstName :: String  
                     , lastName :: String  
                     , age :: Int  
                     , height :: Float  
                     , phoneNumber :: String  
                     , flavor :: String  
                     } deriving (Eq,Show, Read) 

data Car = Car {company :: String, model :: String, year :: Int} deriving (Eq,Show,Read)  

data Things = C Car | P Person deriving (Eq,Show,Read) 

And I want to find the Car's coordinates in a [[Things]].

I tried:

enumerate = zip [0..]

findCar :: [[Things]] -> [(Int, Int)]
findCar things = do
        [(x, y)
          | (y, row) <- enumerate things
          , (x, thing) <- enumerate row
          , thing == C (Car { })]

But I got an Exception: 'Missing field in record construction company'.

How can I find coordinates of Car in a [[Things]] in a proper way?

Upvotes: 1

Views: 687

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 152867

Rather than checking whether your thing is equal to a specific Car, which is what (==) is for, you seem to want to check whether it's any kind of Car. So:

isCar (C Car{}) = True
isCar _ = False

findCar things =
    [ (x, y)
    | (y, row) <- enumerate things
    , (x, thing) <- enumerate row
    , isCar thing
    ]

(I've removed the unnecessary and potentially confusing do from findCar.)

Alternately, you could use the behavior of failed pattern matches in list comprehensions:

findCar things =
    [ (x, y)
    | (y, row) <- enumerate things
    , (x, C Car{}) <- enumerate row
    ]

This is a well-known trick, but a bit subtle and possibly confusing in a quick read of the code (since the match looks partial, but isn't), so it may be worth avoiding in a codebase shared between many programmers.

Upvotes: 5

Related Questions