title: How do I refactor Haskell list Monad code?
body: <p>I recently discovered the <code>guard</code> function associated with the <code>Control.Monad</code> module (defined <a href="http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad.html#v:guard" rel="nofollow noreferrer">here</a>) and it seemed to be a perfect function to solve a common programming challenge: <a href="https://en.wikipedia.org/wiki/Eight_queens_puzzle" rel="nofollow noreferrer">the eight queens problem</a>. I came up with this solution:</p>
  
  <pre class="lang-hs prettyprint-override"><code>import Control.Monad (guard)
  
  type Pair a = (a, a)
  
  eight_queens :: [[Pair Int]]
  eight_queens = do
    r1 &lt;- tag 1 [1..8]
    guard $ all (friendly r1) []
    r2 &lt;- tag 2 [1..8]
    guard $ all (friendly r2) [r1]
    r3 &lt;- tag 3 [1..8]
    guard $ all (friendly r3) [r1, r2]
    r4 &lt;- tag 4 [1..8]
    guard $ all (friendly r4) [r1, r2, r3]
    r5 &lt;- tag 5 [1..8]
    guard $ all (friendly r5) [r1, r2, r3, r4]
    r6 &lt;- tag 6 [1..8]
    guard $ all (friendly r6) [r1, r2, r3, r4, r5]
    r7 &lt;- tag 7 [1..8]
    guard $ all (friendly r7) [r1, r2, r3, r4, r5, r6]
    r8 &lt;- tag 8 [1..8]
    guard $ all (friendly r8) [r1, r2, r3, r4, r5, r6, r7]
    return [r1, r2, r3, r4, r5, r6, r7, r8]
  
  tag :: Int -&gt; [Int] -&gt; [Pair Int]
  tag n = zipWith (,) (repeat n)
  
  friendly :: Pair Int -&gt; Pair Int -&gt; Bool
  friendly cell@(r,c) cell'@(r',c')
    | r == r' = False
    | c == c' = False
    | diagonal cell cell' = False
    | otherwise = True
  
  diagonal :: Pair Int -&gt; Pair Int -&gt; Bool
  diagonal (r,c) (r',c') = abs (r - r') == abs (c - c')
  
  main :: IO ()
  main = print eight_queens
  </code></pre>
  
  <p>The code compiles and gives output that seems mostly correct but I'm trying to refactor to solve the more general n-queens problem with <code>n</code> being passed as an argument to <code>n_queens</code>. The code seems very repetitive suggesting a recursive monadic function could be used but that would remove the found cells from scope. It could also be a fault with using do-notation rather than the bind operator directly.</p>
  
  <p><em>Ignoring the performance and suitability of the algorithm I've used and my coding style like declaring helper functions in top-level namespace.</em></p>