How to do it...

  1. Create a new Haskell project binary-tree-functor using the simple Stack template:
        stack new binary-tree-functor simple
  1. Open src/Main.hs. This is the file that will be used for our purposes.
  2. After adding module definition for Main, add the following import:
        module Main where
import Data.Functor
  1. Define the binary tree and utility functions to create the tree:
        -- The tree can be empty (Leaf) or a node with a 
-- value, left and right trees.
data Tree a = Leaf
| Node (Tree a) a (Tree a)
deriving (Show, Eq)
        -- Create a tree given a value, left tree and a right tree
node :: Tree a -> a -> Tree a -> Tree a
node l x r = Node l x r
       -- Induct a value into a new tree (node with empty left and  
right trees)
singleton :: a -> Tree a
singleton x = Node Leaf x Leaf
  1. Define an instance of a Functor for this binary tree. We have to consider two cases. The first one is what to do when the tree is empty. It is obvious that for an empty tree, the function application is vacuous and would return an empty tree. In the second case, we have a node with a value and two subtrees, that is, left tree and right tree. The function application for Functor will transform the value, and then we can use the definition of fmap recursively to transform the left and right subtrees as well:
        instance Functor Tree where
fmap _ Leaf = Leaf
fmap f (Node left value right) =
Node (fmap f left) (f value) (fmap f right)
  1. Write sample code to test our instance. First, we will create a sample integer tree:
        sampleTree :: Tree Int
sampleTree = node l 1 r
where
l = node ll 2 rl -- l means left, and r means right tree
r = node lr 3 rr
ll = node lll 4 rll -- ll means left subtree of a left node
rl = node lrl 5 rrl -- rl means right subtree of a left
node.
lr = node llr 6 rlr -- and this naming convention continues
rr = node lrr 7 rrr
lll = singleton 8 -- we stop at lll. So lll is a
singleton.
rll = singleton 9 -- all subtrees from this level are
empty
lrl = singleton 10
rrl = singleton 11
llr = singleton 12
rlr = singleton 13
lrr = singleton 14
rrr = singleton 15
  1. In the main function, we will use the show function through Functor to convert a binary tree of integers to a binary tree of strings. We will then use the read function to convert this tree back to a tree of integers. To check that our function implementation is correct, we will check that the original integer tree is the same as the one that we get back after converting from strings:
        main :: IO ()
main = do
let intTree = sampleTree
-- Convert tree of int to tree of strings
stringTree = fmap show intTree
-- We use read to convert it back to tree of ints
intTree1 = fmap (read :: String -> Int) stringTree
putStrLn "Original Tree"
print intTree
putStrLn "Tree of integers to Tree of strings"
print stringTree
putStrLn "Tree of strings converted back to Tree of integers is
same as original tree?"
print $ intTree == intTree1
  1. Build and run the project:
      stack build
stack exec -- binary-tree-functor
  1. You will see the following output: