Cabbage-Goat-Wolf puzzle in Haskell Could you please review the following code, and point out how I can make it cleaner, more idiomatic and easier to understand? 

module Cabbage (
  solve
) where

data Place = Here | There deriving (Eq, Show)

data Pos = Pos { cabb :: Place
               , goat :: Place
               , wolf :: Place
               , farmer :: Place
               } deriving (Eq, Show)

opp :: Place -&gt; Place
opp Here = There
opp There = Here

valid :: Pos -&gt; Bool
valid (Pos {cabb = c, goat = g, wolf = w, farmer = f}) = (c /= g &amp;&amp; g /= w) || g == f

findMoves :: Pos -&gt; [Pos]
findMoves pos@(Pos {cabb = c, goat = g, wolf = w, farmer = f}) =
    filter valid $ moveCabb ++ moveGoat ++ moveWolf ++ moveFarmer where
    moveCabb | c == f = [pos {cabb = opp c, farmer = opp f}] | otherwise = []
    moveGoat | g == f = [pos {goat = opp g, farmer = opp f}] | otherwise = []
    moveWolf | w == f = [pos {wolf = opp w, farmer = opp f}] | otherwise = []
    moveFarmer = [pos {farmer = opp f}]

findSolution :: Pos -&gt; Pos -&gt; [Pos]
findSolution from to = head $ loop [[from]] where
    loop pps = do ps &lt;- pps
                  let moves = filter (flip notElem ps) $ findMoves $ head ps
                  if to `elem` moves
                    then return $ reverse $ to:ps
                    else loop $ map (:ps) moves

solve :: [Pos]
solve = findSolution (setAll Here) (setAll There) where
            setAll x = Pos{ cabb = x, goat = x, wolf = x, farmer = x }


IMHO the findMoves function seems to be quite verbose, and the findSolutions function looks confusing.

Thank you!
Haskell's record system is not really good at providing you uniform access to record entries. That is the reason your findMoves implementation has to be so verbose: You cannot generalize over the fields.

There are a number of ways to get around that. One could be using a library such as fclabels that facilitates this job for you. You set it up like follows:

import Data.Record.Label

data Pos = ....

$( mkLabels [''Pos] )


This will give you "labels" with names such as lCabb that you can use with functions such as getL or modL. Without all this boilerplate, it is possible to write a much more satisfying findMoves function:

findMoves :: Pos -&gt; [Pos]
findMoves pos = filter valid moves
  where
    moves    = [ foldr (\obj -&gt; modL obj opp) pos objs
               | objs &lt;- moveComb, same $ map (`getL` pos) objs
               ]
    moveComb = [[lCabb, lFarmer], [lGoat, lFarmer], [lWolf, lFarmer], [lFarmer]]
    same xs  = all (== head xs) xs