1
votes

I've just started to learn Haskell and for practice I've decided to create a function that takes a tree, whose elements have a position and size, and returns the element located at a certain position. My code looks like this:

import Data.List (dropWhile)

data Node = Node (Int,Int) (Int,Int) [Node] deriving(Eq, Show)

findNode :: (Int,Int) -> Node -> Maybe Node
findNode loc node@(Node (x, y) (width, height) []) = if loc >= (x, y) && loc <= (x+width, y+height) then Just node else Nothing
findNode loc node@(Node (x, y) (width, height) children) = 
    if loc >= (x, y) && loc <= (x+width, y+height)
        then if not $ null nodes then
            head nodes
        else
            Just node
    else Nothing
    where nodes = dropWhile (==Nothing) $ map (findNode loc) children

This code compiles and runs perfectly as far as I can tell, but I'm curious about one thing, Why is head nodes acceptable instead of Just $ head nodes?.

1

1 Answers

6
votes

That's because your nodes has a type of [Maybe Node]. You can infact verify that by annotating it explicitly and compiling it again:

findNode loc node@(Node (x, y) (width, height) children) = 
  if loc >= (x, y) && loc <= (x+width, y+height)
  then
    if not $ null nodes
    then head nodes
    else Just node
  else Nothing
  where
    nodes = dropWhile (==Nothing) $ map (findNode loc) children :: [Maybe Node]

So how does, nodes have [Maybe Node] type ?

The type of map (findNode loc) children is [Maybe Node]. (General type of map is map :: (a -> b) -> [a] -> [b] and in your case the type of findNode loc is Node -> Maybe Node and hence the resultant type is [Maybe Node] ). And the type of dropWhile is (a -> Bool) -> [a] -> [a]. In your case a already is Maybe Node and hence your nodes has a type of [Maybe Node].