簡體   English   中英

如何重構 Haskell 列表 Monad 代碼?

[英]How do I refactor Haskell list Monad code?

我最近發現了與Control.Monad模塊( 在此處定義)相關聯的guard函數,它似乎是解決常見編程挑戰的完美函數:八皇后問題 我想出了這個解決方案:

import Control.Monad (guard)

type Pair a = (a, a)

eight_queens :: [[Pair Int]]
eight_queens = do
  r1 <- tag 1 [1..8]
  guard $ all (friendly r1) []
  r2 <- tag 2 [1..8]
  guard $ all (friendly r2) [r1]
  r3 <- tag 3 [1..8]
  guard $ all (friendly r3) [r1, r2]
  r4 <- tag 4 [1..8]
  guard $ all (friendly r4) [r1, r2, r3]
  r5 <- tag 5 [1..8]
  guard $ all (friendly r5) [r1, r2, r3, r4]
  r6 <- tag 6 [1..8]
  guard $ all (friendly r6) [r1, r2, r3, r4, r5]
  r7 <- tag 7 [1..8]
  guard $ all (friendly r7) [r1, r2, r3, r4, r5, r6]
  r8 <- 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 -> [Int] -> [Pair Int]
tag n = zipWith (,) (repeat n)

friendly :: Pair Int -> Pair Int -> Bool
friendly cell@(r,c) cell'@(r',c')
  | r == r' = False
  | c == c' = False
  | diagonal cell cell' = False
  | otherwise = True

diagonal :: Pair Int -> Pair Int -> Bool
diagonal (r,c) (r',c') = abs (r - r') == abs (c - c')

main :: IO ()
main = print eight_queens

代碼編譯並提供似乎大部分正確的輸出,但我正在嘗試重構以解決更一般的 n-queens 問題,其中n作為參數傳遞給n_queens 該代碼似乎非常重復,表明可以使用遞歸 monadic 函數,但這會從范圍中刪除找到的單元格。 使用 do-notation 而不是直接使用綁定運算符也可能是一個錯誤。

忽略我使用的算法的性能和適用性以及我的編碼風格,比如在頂級命名空間中聲明輔助函數。

您可以在保留已放置的皇后列表的同時進行遞歸:

place :: Int -> [Pair Int] -> [[Pair Int]]
place 9 placed = return placed
place n placed = do
   r <- tag n [1..8]
   guard $ all (friendly r) placed
   place (n + 1) (r : placed)

eight_queens :: [[Pair Int]]
eight_queens = place 1 []

第一個Int參數是下一個要放置的皇后的標簽,第二個[Pair Int]參數是已經放置的皇后列表。

(這將按照與您的代碼相反的順序返回皇后。如果您需要該順序,請改用return (reverse placed) 。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM