Kirk Broadhurst
Kirk Broadhurst

Reputation: 28738

Retrieve values from datatype

I'm trying to implement an object graph in Haskell, and I have a simple Node type which contains a identifier and a list of connected nodes.

data Node = Node Integer [Node] deriving (Show)

My problem is operating on these types - specifically retrieving the values. For example, I want to look at the Integer value within the node; maybe find the item with id = 0

nodes = [Node 0 []]
[n | n <- nodes, fst n == 0]

• Couldn't match expected type ‘(Integer, b0)’
                  with actual type ‘Node’
    • In the first argument of ‘fst’, namely ‘n’
      In the first argument of ‘(==)’, namely ‘fst n’
      In the expression: fst n == 0

Okay, so I can't use fst. I can't use !! either. I can write a function that pulls out the value like

nodeId :: Node -> Integer
nodeId (Node i _) = i

and now [n | n <- nodes, nodeId n == 0] will work.

Is there another way to get values from datatypes like this? Is this the right pattern?

Upvotes: 0

Views: 216

Answers (2)

Carcigenicate
Carcigenicate

Reputation: 45816

You could also use record syntax to generate accessor functions for the fields:

data Node = Node { nodeId :: Integer,
                   children :: [Node]
                 } deriving (Show)

[n | n <- nodes, nodeId n == 0]

Although this has the downside that it's polluting; it creates functions based on the field names. That means you can't have two records that have fields with the same name. You also can't have your own functions with the same name as the field name of the record.

As @K. A. Buhr mentions though, GHC does have an extension to help alleviate at least one of these problems.

Upvotes: 5

amalloy
amalloy

Reputation: 92117

The only way to get values out of a data constructor is indeed to pattern-match on it. If you want, you can define a function that does it, as you have done with nodeId, or you can just do the pattern matching inline. For example, you could write

[n | n@(Node id _) <- nodes, id == 0]

Or, since a list comprehension skips values for which a pattern fails, a shorter version would be

[n | n@(Node 0 _) <- nodes]

Upvotes: 8

Related Questions