I'll assume you defined
data MyTree x = MyLeaf x | MyNode (MyTree x) (MyTree x)
and meant
myFunction :: MyTree x -> (x, Maybe(MyTree x))
myFunction (MyLeaf x) = (x, Nothing)
myFunction (MyNode left right) = case myFunction left of
(x, Nothing) -> (x, Just right)
(x, Just left2) -> (x, Just (MyNode left2 right))
Which is a function that pulls out the leftmost leaf and sews the corresponding right branch in where it was.
You ask how to make this tail recursive. Why is that? In some (strict) languages, tail recursive code is more efficient, but Haskell uses lazy evaluation, which means it doesn't matter how late the recursive calls happen, but rather how early they produce output. In this case, the head recursive case myFunction left of
zooms right down the tree until it finds that leftmost leaf, you can't get to it any quicker. However, on the way back up, it does pass the x
around a bit rather than returning immediately, but it also sews all the right branches back on at the appropriate plave without any bookkeeping, which is the joy of using recursion on a recursive data structure.
See this question about why tail recursion isn't the most important thing for efficiency in Haskell.
Three classic things to do to a binary tree with data at the nodes are:
1. pre-order traversal (visit the current node first then the left subtree then right) - doubly tail recursive
2. in-order traversal (visit left subtree, then current node, then right) - head and tail recursive
3. post-order traversal (visit left and right subtrees before the current node) - doubly head recursive.
Post order sounds worryingly head recursive to someone not used to lazy evaluation, but it's an efficient way to sum the values in your tree, for example, particularly if you make sure the compiler knows it's strict.
As always, the best algorithms give the fastest results, and you should compile with -O2 if you want optimisations turned on.