Haskell中的递归混淆
我希望有人能帮我找出我的错误所在。调用Haskell中的递归混淆,haskell,recursion,Haskell,Recursion,我希望有人能帮我找出我的错误所在。调用g34002(M.empty,0)[,我希望结果是[[2,1,0,1]]。相反,我看到的是[[2,1,0,1],[2,1,0,1]] 程序应该通过每次向列表中添加不同的数字来累积长度为m的不同数字模式,当到达n-1时返回向下,当到达0时返回向上。表观问题发生在中间,当函数被上下方向递归调用时。p> 如果我这样注释第11行: else g n m (digitCount + 1) (lastDigit + 1) (hash',hashCount') (last
g34002(M.empty,0)[
,我希望结果是[[2,1,0,1]]
。相反,我看到的是[[2,1,0,1],[2,1,0,1]]
程序应该通过每次向列表中添加不同的数字来累积长度为m
的不同数字模式,当到达n-1
时返回向下,当到达0
时返回向上。表观问题发生在中间,当函数被上下方向递归调用时。p>
如果我这样注释第11行:
else g n m (digitCount + 1) (lastDigit + 1) (hash',hashCount') (lastDigit:digits)
-- g n m (digitCount + 1) (lastDigit - 1) (hash',hashCount') (lastDigit:digits)
我得到了正确的结果[]
当注释掉第11行并将第10行修改为:
else g n m (digitCount + 1) (lastDigit - 1) (hash',hashCount') (lastDigit:digits)
同样,正确的结果[[2,1,0,1]]
为什么在使用++
操作符调用g
两次时,我得到的是两个[2,1,0,1]
?在我看来,g
中的每个结果都应该是不同的,因为在任何递归调用中,不同顺序的数字正在(或应该)累积
提前谢谢
import qualified Data.Map as M
g :: Int -> Int -> Int -> Int -> (M.Map Int Bool, Int) -> [Int] -> [[Int]]
g n m digitCount lastDigit (hash,hashCount) digits
| digitCount == m = if test then [reverse digits] else []
| otherwise =
if lastDigit == 0
then g n m (digitCount + 1) (lastDigit + 1) (hash',hashCount') (lastDigit:digits)
else if lastDigit == n - 1
then g n m (digitCount + 1) (lastDigit - 1) (hash',hashCount') (lastDigit:digits)
else g n m (digitCount + 1) (lastDigit + 1) (hash',hashCount') (lastDigit:digits)
++ g n m (digitCount + 1) (lastDigit - 1) (hash',hashCount') (lastDigit:digits)
where test = hashCount == n
(hash',hashCount') =
if test
then (M.empty,hashCount)
else case M.lookup lastDigit hash of
Just anyting -> (hash,hashCount)
Nothing -> (M.insert lastDigit True hash,hashCount + 1)
在最后一个else分支中,对
g
的两个递归调用与(++)
结合使用时,除了lastDigit
之外,传递的参数完全相同
递归的基本情况不是查看lastDigit
——它只是比较m
和digitCount
,n
和hashCount
,然后返回[反向数字]
因此,在任何情况下,(++)
大小写被立即命中,然后基本大小写返回[反向数字]
,您将得到相同的重复值
我没有完全理解您的问题说明,但在进行递归调用时,您可能需要将
lastDigit
的“新”值添加到digits中,即(lastDigit-1):digits
或(lastDigits+1):digits
在对g
的两次递归调用中与(++)结合使用
在最后一个else分支中,除了lastDigit
之外,您传递的参数完全相同
递归的基本情况不是查看lastDigit
——它只是比较m
和digitCount
,n
和hashCount
,然后返回[反向数字]
因此,在任何情况下,(++)
大小写被立即命中,然后基本大小写返回[反向数字]
,您将得到相同的重复值
我没有完全理解您的问题说明,但在进行递归调用时,您可能需要将lastDigit
的“新”值添加到digits,即(lastDigit-1):digits
或(lastDigit+1):digits
为什么在使用++运算符两次调用g时,我得到的是两个[2,1,0,1],而不是一个[2,1,0,1]
一在我看来,g中的每个结果都应该是不同的,因为在任何递归调用中
不同的数字顺序正在(或应该)累积
但是两个调用中的(Map,Int)对是相同的,因此递归调用不知道另一个调用找到了什么。考虑调用G…(最后一位数字-1)。它也会叫g。。。(lastDigit)(通过将1添加到它得到的(lastDigit-1)中),并遵循分支g。。。(lastDigit+1)生成相同的结果
另外,(Map a())是(Set a),因为不使用Map中的Bool值,所以它与()相同:
导入符合条件的数据。设置为S
g::Int->Int->Int->Int->(S.Set Int,Int)->[Int]->[[Int]]
g n m digitCount lastDigit(哈希、哈希计数)位数
|digitCount==m=如果测试,那么[reverse digits]else[]
|lastDigit<0 | | lastDigit==n=[]
|否则=g n m d'(最后一位数+1)h'(最后一位数:位数)
++g n m d'(最后一位数-1)h'(最后一位数:位数)
其中test=hashCount==n
d'=数字计数+1
h'
|test=(S.empty,hashCount)
|S.member lastDigit哈希=(哈希,哈希计数)
|否则=(S.insert lastDigit散列,hashCount+1)
为什么在使用++运算符两次调用g时,我得到的是两个[2,1,0,1],而不是一个[2,1,0,1]
一在我看来,g中的每个结果都应该是不同的,因为在任何递归调用中
不同的数字顺序正在(或应该)累积
但是两个调用中的(Map,Int)对是相同的,因此递归调用不知道另一个调用找到了什么。考虑调用G…(最后一位数字-1)。它也会叫g。。。(lastDigit)(通过将1添加到它得到的(lastDigit-1)中),并遵循分支g。。。(lastDigit+1)生成相同的结果
另外,(Map a())是(Set a),因为不使用Map中的Bool值,所以它与()相同:
导入符合条件的数据。设置为S
g::Int->Int->Int->Int->(S.Set Int,Int)->[Int]->[[Int]]
g n m digitCount lastDigit(哈希、哈希计数)位数
|digitCount==m=如果测试,那么[reverse digits]else[]
|lastDigit<0 | | lastDigit==n=[]
|否则=g n m d'(最后一位数+1)h'(最后一位数:位数)
++g n m d'(最后一位数-1)h'(最后一位数:位数)
其中test=hashCount==n
d'=数字计数+1
h'
|test=(S.empty,hashCount)
|S.member lastDigit哈希=(哈希,哈希计数)
|否则=(S.insert lastDigit散列,hashCount+1)
现在您已经可以使用它了,这里有一个更通用的方法
我们需要走解决方案之树
data S a = Solution a | Explore [S a]
解决方案是这棵树的叶子,探索是要探索的选项列表
-- this is very much unfoldr-like
generator :: [S a] -> [a]
generator [] = []
generator (Solution a: ss) = a: generator ss
generator (Explore ps: ss) = generator $ ss ++ ps
main = print $ map reverse $ generator $ g 3 6
现在,给出一个“可能的解决方案”列表,生成一个解决方案列表。生成器模式匹配Explores,并将要探索的解决方案列表附加到列表的末尾。这样我们就在探索
g :: Int -> Int -> [S [Int]]
g n m = [Explore $ g' [i] (S.singleton i) | i <- [1..n-1]] where
g' is@(h:_) ms
| h < 0 || h >= n || length is > m = [] --no solution, nothing to explore
| otherwise = maybeSolution ++
[ Explore $ g' ((h-1):is) $ S.insert (h-1) ms
, Explore $ g' ((h+1):is) $ S.insert (h+1) ms ]
where
maybeSolution
| S.size ms == n = [Solution is]
| otherwise = []
main = print $ map reverse $ generator $ g 3 6