我正在尝试使用深度优先搜索算法中的地图来测试路径,以便在未定向的迷宫中包含目标单元格,并且没有循环。我遇到麻烦的地方是使用map进行递归调用。
这是我的代码:
type Maze = [[Cell]]
data Cell = Cell { top, left, right, bottom :: Bool }
type Pos = (Int, Int)
type Path = [Pos]
findPath :: Maze -> Path
findPath [] = []
findPath maze = dfs maze [] (-1,-1) (1,1)
dfs :: Maze ->Path -> Pos -> Pos -> Path
dfs maze trail prev curr
| (curr == goal) = reverse $ goal : trail -- ?
| (null adj) = []
| otherwise = dfs maze (curr : trail) curr `map` (adj c (fst curr) (snd curr) prev)
where c = maze!!(fst curr- 1)!!(snd curr - 1)
goal = (length maze, length (maze!!0))
adj:: Cell -> Int -> Int -> Pos ->Path
adj c x y prev = if (top c && prev /= (x-1, y)) then [(x-1, y)] else [] ++
if (left c && prev /= (x, y-1)) then [(x, y-1)] else [] ++
if (right c && prev /= (x, y+1)) then [(x, y+1)] else [] ++
if (bottom c && prev /= (x+1, y)) then [(x+1, y)] else []
我对dfs maze (curr : trail) curr 'map' (adj c (fst curr) (snd curr) prev)
的期望是我将函数f::Pos->trail
应用于[Pos]
中的每个元素,但(curr : trail)
给出的是[Path]
而不是Path
一个stack: WARNING! Expecting stack options comment at line 1, column 1
stack: WARNING! Missing or unusable stack options specification
stack: WARNING! Using runghc without any additional stack options
SolveMaze.hs:77:24: error:
* Couldn't match type `[Pos]' with `(Int, Int)'
Expected type: Path
Actual type: [Path]
* In the expression:
dfs maze (curr : trail) curr
`map` (adj c (fst curr) (snd curr) prev)
In an equation for `dfs':
dfs maze trail prev curr
| (curr == goal) = reverse $ goal : trail
| (null adj) = []
| otherwise
= dfs maze (curr : trail) curr
`map` (adj c (fst curr) (snd curr) prev)
where
c = maze !! (fst curr - 1) !! (snd curr - 1)
goal = (length maze, length (maze !! 0))
|
77 | | otherwise = dfs maze (curr : trail) curr `map` (adj c (fst curr)
(snd curr) prev)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^
错误堆栈给我如下:
{{1}}
我很抱歉,如果这对你来说是一个非常基本的问题Haskell巫师,但我一直盯着这个问题已经很长时间了,我不能接受它,需要寻求帮助。谢谢。
答案 0 :(得分:1)
让我们放大两行。首先是dfs的类型:
dfs :: Maze ->Path -> Pos -> Pos -> Path
完全应用后,dfs会返回Path
,很棒。
我们还有dfs的定义,它必须返回一个Path,是:
dfs maze (curr : trail) curr `map` (adj c (fst curr) (snd curr) prev)
或者通过一些简化来明确发生了什么:
map (dfs and some args) (some list)
所以dfs必须返回一个路径,所以说类型,但定义显示它返回一个路径列表。
你似乎想要的是尝试下降到一个相邻位置并执行深度优先搜索然后下降到下一条可能的路径,利用沿途的懒惰评估 - 太棒了!
让我们更改dfs以返回路径列表([Path]
) - 如果找到死角,它将是解决方案列表或非解决方案([]
)。将reverse ...
更改为[reverse ...]
。和map
到concatMap
。
询问某个函数是否为null是没有意义的,我认为您对adj
的{{1}}的应用程序有所了解。
现在,查找路径必须选择dfs现在返回的解决方案列表之一 - 第一个应该足够了。您可以使用null (adj c (fst curr) ...
获得listToMaybe
结果。
Maybe Path
如果您愿意,还有很多其他事情可以清理。
import Data.Maybe (listToMaybe)
type Maze = [[Cell]]
data Cell = Cell { top, left, right, bottom :: Bool }
type Pos = (Int, Int)
type Path = [Pos]
findPath :: Maze -> Maybe Path
findPath [] = Just []
findPath maze = listToMaybe $ dfs maze [] (-1,-1) (1,1)
dfs :: Maze ->Path -> Pos -> Pos -> [Path]
dfs maze trail prev curr
| (curr == goal) = [reverse $ goal : trail] -- ?
| (null adjVal) = []
| otherwise = dfs maze (curr : trail) curr `concatMap` adjVal
where c = maze!!(fst curr- 1)!!(snd curr - 1)
goal = (length maze, length (maze!!0))
adjVal = adj c (fst curr) (snd curr) prev
adj:: Cell -> Int -> Int -> Pos ->Path
adj c x y prev = if (top c && prev /= (x-1, y)) then [(x-1, y)] else [] ++
if (left c && prev /= (x, y-1)) then [(x, y-1)] else [] ++
if (right c && prev /= (x, y+1)) then [(x, y+1)] else [] ++
if (bottom c && prev /= (x+1, y)) then [(x+1, y)] else []
表示失败的路径,而不是[]
。如果第一次深度优先搜索失败,那么您返回的“解决方案”将为Maybe Path
。[]
并假设输入没有锯齿状。你可以使用数组。!!
的详细定义。