在本主题中: How find path at the m x n table 我发现了如何在两点之间生成路径,这就是代码:
go m n (i,j) =
[ (i+1,j) | i<m ] ++
[ (i-1,j) | i>1 ] ++
[ (i,j+1) | j<n ] ++
[ (i,j-1) | j>1 ]
-- isEndOfPath p q = (p == q)
genPath p q acc m n input buf = g p q acc buf where
g p q acc buf | p==q = [(acc)] -- return acc, buf
g p q acc buf = [s
| r <- go m n q, notElem r buf, notElem r acc,
notElem r input,
s <- genPath p r (r:acc) m n input (r:buf)] ++
[s
| r <- go m n q, notElem r acc,
r==p,
s <- genPath p r (r:acc) m n input (r:buf)]
例如,我们可以在2x2上搜索从(2,2)到(1,1)的路径。因此,我们可以将其称为
genPath (2,2) (1,1) [(1,1)] 2 2 [(3,3),(1,1)] [(1,1)]
我们有结果
[[(2,2),(2,1),(1,1)],[(2,2),(2,1),(1,1)],[(2,2),(1,2),(1,1)],[(2,2),(1,2),(1,1)]]
所以我们有正确的路径。
现在我将找到成对点之间的所有路径。在Prolog中,它非常简单,我对此没有任何问题。所以,我可以告诉你我的算法和代码:
第一个谓词 - 当我们找到所有路径时,我们将其返回:
genAllPaths([],A,A,_,_,_,_).
否则,我们必须递归地生成路径。所以,我们在第一对之间找到路径,然后我们可以搜索其他路径:
genAllPaths([(I1,J1),(I2,J2)|T],Acc,S,M,N,Input,Bufor) :-
genPath((I1,J1),(I2,J2),[(I2,J2)],X,M,N,Input,[(I2,J2)|Bufor],NewBufor),
genAllPaths(T,[X|Acc],S,M,N,Input,NewBufor).
如果你不明白,请问我。
因此,现在我将在哈斯克尔进行。我试过了,但是我又遇到了很多问题。如果你知道怎么做并希望帮助我 - 我将非常感激。
答案 0 :(得分:1)
go m n (i,j) =
[ (i+1,j) | i<m ] ++
[ (i-1,j) | i>1 ] ++
[ (i,j+1) | j<n ] ++
[ (i,j-1) | j>1 ]
genPath p q acc m n input buf = g p q acc buf -- return all solutions
where
g p q acc buf | p==q = [(acc,buf)] -- return acc, buf
g p q acc buf = [s |
r <- go m n q, notElem r buf, notElem r acc,
notElem r input,
s <- g p r (r:acc) (r:buf)] ++
[s |
r <- go m n q, notElem r acc,
r==p,
s <- g p r (r:acc) (r:buf)]
您的新代码:
genAllPaths([],A,A,_,_,_,_).
genAllPaths([(I1,J1),(I2,J2)|T],Acc,S,M,N,Input,Bufor) :-
genPath((I1,J1),(I2,J2),[(I2,J2)],X,M,N,Input,[(I2,J2)|Bufor],NewBufor),
genAllPaths(T,[X|Acc],S,M,N,Input,NewBufor).
直接将文本翻译成Haskell是:
genAllPaths points acc m n input buf = g points acc buf where
g [] acc _ = [acc]
g (p:q:t) acc buf =
let sols = genPath p q [q] m n input (q:buf) -- => [(x,newbuf)]
in concat [g t (x:acc) newbuf | (x,newbuf) <- sols]
另一种写作方式是
genAllPaths points acc m n input buf = g points acc buf where
g [] acc _ = [acc]
g (p:q:t) acc buf =
genPath p q [q] m n input (q:buf) >>= (\ (x,newbuf) ->
g t (x:acc) newbuf )
这使用列表monad中的 bind 运算符>>=
。还有do
符号,
genAllPaths points acc m n input buf = g points acc buf where
g [] acc _ = return acc -- same as writing `[acc]`, for list monad
g (p:q:t) acc buf =
do
(x,newbuf) <- genPath p q [q] m n input (q:buf)
g t (x:acc) newbuf
表示在没有明确使用 bind 的情况下进行相同的计算。 List monad通过将所有可能的选择表示为列表来表示非确定性计算。真实的表示将使用具有不可预测顺序的无序列表;正常的Haskell列出了诱导顺序,但Prolog从左到右的自上而下的策略也是如此。
由于Haskell是懒惰的,因此逐个生成结果解决方案等同于Prolog的回溯搜索,take 1
可用于模拟cut
。