I've bumped into this brain teaser recently:
"Given two integer numbers describing an n by m graph, where n represents the height and m represents the width, calculate the number of ways you can get from the top left to the bottom right if you can only go right and down"
That's a fine challenge, and prior to knowing recursive types in Haskell, I don’t know how I would have approached the problem.
Let's draw what the paths would look like first.
Given 1x1, the case is pretty simple:
{-
  The is what the matrix would look like:
  (0,1) - (1,1)
    |       |
  (0,0) - (1,0)
-}
The only way to get from the top left to the bottom right is to "walk" the perimeters:
{-
  (0,1) - (1,1) - (1,0)
  (0,1) - (0,0) - (1,0)
-}
This case is so easy, I don’t even bother with devising a solution. Let's look at a 1 by 2 graph:
{-
  (0-1) - (1,1) - (2,1)
    |       |       |
  (0-0) - (1,0) - (2,0)
-}
Following the rules laid out, there are 3 ways to get from the top left to the bottom right point:
{-
  (0-1) - (1,1) - (2,1) - (2,0)
  (0-1) - (1,1) - (1,0) - (2,0)
  (0-1) - (0,0) - (1,0) - (2,0)
-}
The rule "you can only go right and down" tells us something: it's a binary tree. How could I draw up a recursive tree structure for this?
I'd like to make sure the logic is correct, I put all this logic into an HSpec file. How 'bout this?
-- test/PathCountSpec.hs
import Test.Hspec
main :: IO ()
main = hspec spec
type Point = (Int, Int)
data Tree a = Leaf
            | Node a (Tree a) (Tree a)
            deriving (Show, Eq)
spec :: Spec
spec =
    describe "Path Count" $ do
        it "can calculate tree branches for 1x2 matrix" $ do
            let tree =
                    Node (0,1)
                        (Node (1,1)
                            (Node (2,1) Leaf
                                        (Node (2,0) Leaf Leaf))
                            (Node (1,0) (Node (2,0) Leaf Leaf)
                                        Leaf))
                        (Node (0,0)
                            (Node (1,0)
                                (Node (2,0) Leaf Leaf)
                                Leaf)
                            Leaf)
            {-
               Possible paths:
                (0,1) - (1,1) - (2,1) - (2,0)
                (0,1) - (1,1) - (1,0) - (2,0)
                (0,1) - (0,0) - (1,0) - (2,0)
            -}
            pending
The key here, that the number of times Node (2,0) Leaf Leaf appears is the number of different ways I can get from the top left to the bottom right. All I have to do is counting the number of times this sub-tree appears in the tree itself.
I wrote a function (that I put into the HSpec file itself) to do just that:
leafCount :: Tree Point -> Int leafCount Leaf = 0 leafCount (Node _ Leaf Leaf) = 1 leafCount (Node _ left right) = leafCount left + leafCount right
When I call this function with the provided tree I have in the spec, I should receive 3. This assertion passes:
leafCount tree `shouldBe` 3
I manually had to build up this tree, next I looked at how I could generate it myself based on the top left and bottom right points. I had to make sure I won’t add branches outside of the matrix, what I accomplished with two guards.
buildTree :: Point -> Point -> Tree Point
buildTree (a,b) end@(c,d)
    | a > c = Leaf
    | b < 0 = Leaf
    | otherwise = Node (a, b) (buildTree (a+1,b) end) (buildTree (a,b-1) end)
This logic will keep "walking" right and down until the guards will stop it.
I added another assertion to make sure this still passes:
buildTree (0,1) (2,0) `shouldBe` tree
I wanted to make sure this logic still holds when I pivot the two numbers. This is the next assertion I added:
buildTree (0,2) (1,0) `shouldBe` tree
Tests are passing. All right, I need to set up an outer function that takes two numbers and returns the number of paths.
Here it is:
pathCount :: Int -> Int -> Int
pathCount m n = leafCount $ fromTree m n
    where fromTree m n = buildTree (0,m) (n,0)
This assertion will exercise this function:
pathCount 1 2 `shouldBe` 3
Everything is green!
I added one more test to make sure the 1x1 graph works:
pathCount 1 1 `shouldBe` 2
And finally I added a 2x2 test as well. This one has 6 different paths to get from the top left to the bottom right:
{-
    Possible paths:
    (0,2) - (1,2) - (2,2) - (2,1) - (2,0)
    (0,2) - (1,2) - (1,1) - (2,1) - (2,0)
    (0,2) - (1,2) - (1,1) - (1,0) - (2,0)
    (0,2) - (0,1) - (1,1) - (2,1) - (2,0)
    (0,2) - (0,1) - (1,1) - (1,0) - (2,0)
    (0,2) - (0,1) - (0,0) - (1,0) - (2,0)
-}
pathCount 2 2 `shouldBe` 6
And when I run the spec again, it all works! You can find the solution in this gist.
 
