2

I am trying to define a multi-way tree data type in ghci. Each node has a key and a value. Here is the related code:

    data Tree k v = Empty |
                    N {key::k,
                       value::v} [Tree k v]
                  deriving (Show, Eq)

Here is corresponding output from Ghci:

    Not in scope: `key'
    Not in scope: `value'

I checked the syntax of the record by defining the tree node record separately using the following code:

   data Node k v = Node { key::k
                        , value::v}
                 deriving (Show, Eq)

This works as expected. What is causing my Tree data type definition to throw this error? Am I missing something related to record syntax when used to define an alternate value constructor?

1
  • 1
    Note that the record accessors are functions in the module scope. So key and value are now functions that might override any other definition. This is why you usually see treeValue instead of just value. Commented Apr 11, 2014 at 20:21

2 Answers 2

4

When using the record syntax with ADTs, all constructors must have the same fields. Additionally, you're attempting to combine record and normal constructor syntax with Node { key :: k, value :: v } [Tree k v]. Instead, you'll have to resort to normal positional arguments to your constructor like

data Tree k v
    = Emtpy
    | N k v [Tree k v]
    deriving (Eq, Show)

You could use record syntax with ADTs as

data Tree k v
    = RedNode   { key :: k, val :: v, children :: [Tree k v] }
    | BlackNode { key :: k, val :: v, children :: [Tree k v] }
    deriving (Eq, Show)

But I would recommend making a separate data type as

data Color = Red | Black deriving (Eq, Show)

data Tree k v = Node
    { color :: Color
    , key :: k
    , val :: v
    , children :: [Tree k v]
    } deriving (Eq, Show)

Because then if you extend Color, you have less typing, and I would argue that it's more idiomatic.

Sign up to request clarification or add additional context in comments.

1 Comment

Nit-pick all constructors don't have to have the same fields. When not all fields are present on all constructors, you get accessors that are partial: Prelude> data Foo = Empty | One { only :: String } | More { than_ever :: [Int] } Prelude> :t Empty Empty :: Foo Prelude> :t One "Another" One "Another" :: Foo Prelude> :t More [2, 4] More [2, 4] :: Foo Prelude> only $ More [2, 4] "*** Exception: No match in record selector only Prelude> than_ever Empty *** Exception: No match in record selector than_ever
1

If you want to use a separate node type, you may be looking for something like

data Tree k v = Empty | N (Node k v) [Tree k v]
              deriving (Show, Eq)

data Node k v = Node { key::k
                     , value::v}
              deriving (Show, Eq)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.