我想了解Select
monad是如何工作的。显然,它是Cont
的表亲,它可以用于回溯搜索。如何使用Select monad来解决n皇后问题?
我有这个基于列表的解决N皇后问题:
-- All the ways of extracting an element from a list.
oneOf :: [Int] -> [(Int,[Int])]
oneOf [] = []
oneOf (x:xs) = (x,xs) : map (\(y,ys) -> (y,x:ys)) (oneOf xs)
-- Adding a new queen at col x, is it threathened diagonally by any of the
-- existing queens?
safeDiag :: Int -> [Int] -> Bool
safeDiag x xs = all (\(y,i) -> abs (x-y) /= i) (zip xs [1..])
nqueens :: Int -> [[Int]]
nqueens queenCount = go [] [1..queenCount]
where
-- cps = columsn of already positioned queens.
-- fps = columns that are still available
go :: [Int] -> [Int] -> [[Int]]
go cps [] = [cps]
go cps fps = [ps | (p,nfps) <- oneOf fps, ps <- go (p:cps) nfps, safeDiag p cps]
我努力适应这个解决方案中使用Select
代替。
看来Select
可以让你抽象出用于比较答案的“评估函数”。该功能传递给runSelect
。我感觉像我的解决方案中的safeDiag
这样的东西可以用作评估函数,但是如何构造Select
计算本身?
另外,仅使用Select
monad就足够了,还是我需要在列表上使用变换器版本?
您确定要“选择”monad吗?我对“选择”的理解是它试图证明存在一种可能的解决方案(作为证明证明)。 “Select”的典型例子是SAT求解器。你可能会用'SelectT'强制通过列表monad,但我更确定你会真正使用select monad。 – Alec
@Alec我读过“Select”适用于回溯搜索,而n-queens是这种类型的原型问题,所以我认为这对monad来说是一个很好的用例。 – danidiaz
区别可能是回溯到找到所有解决方案和回溯,直到找到解决方案。然后,我再一次只玩过“选择”,所以不要拿任何我认真说的话。 – Alec