Well, our goal is to put this function in Votier's monad.
reaches :: KnightPos -> KnightPos -> Int -> Bool reaches _ _ 0 = False reaches from pos n = any (\p -> p == pos || reaches p pos (n-1)) $ moveKnight from
So, let's start with a type signature. Just add Writer around the result type:
reaches :: KnightPos -> KnightPos -> Int -> Writer [String] Bool
The original function did not return [Bool] , so there is no reason for the new function to return Writer [String] [Bool] . Raise the return value of the base case:
reaches _ _ 0 = return False
As you suspected, for a recursive case it gets a little harder. Start by tell current pos , which you did correctly.
reaches from pos n = do tell ["-->" ++ show pos]
moveKnight not in the writer's monad, so we don’t need to bind it with <- to invoke it. Just use let (i.e. we can substitute moveKnight pos whenever we use our new variable if we want):
let moves = moveKnight from
Now let's get a list of recursive results. This time we need to bind, since we get the Bool from the Writer [String] Bool . We will use the monadic version of map , mapM :: (a -> mb) -> [a] -> m [b] :
np <- mapM (\p -> reachesm p pos (n-1)) ps
Now np :: [Bool] . So, we just finish your logic:
return (any (pos ==) moves || or np)
or :: [Bool] -> Bool is just any id .
So remember to bind the variable when you want to get a from ma , use <- , otherwise use let .
To use it from main , you can use runWriter :: Writer wa -> (w,a) :
main = print $ runWriter (reachesm (6,2) (6,1) 3)
This code still has an error, but it compiles and gives what you told him on the write channel, so it should be enough so that you can easily debug the remaining problem. Hope this helps.