我正在尝试在Haskell中实现着名的Verbal算术问题(SEND + MORE = MONEY)。对于那些不了解口头算术的人 - https://en.wikipedia.org/wiki/Verbal_arithmetic。
这是我的示例程序,但由于某种原因它不起作用,它返回一个空列表。任何人都可以指出代码中的缺陷并提出一些建议吗?我卡住了,谢谢!
expand' a b c d e = e + d*10 + c*100 + b*1000 + a*10000
expand'' a b c d = d + c*10 + b*100 + a*1000
digits = [0,1..9] -- all the digits
answer = head [ list | list@[s,e,n,d,m,o,r,y] <- perm digits,
expand'' s e n d + expand'' m o r e == expand' m o n e y]
--unique permutation
perm :: [t] -> [[t]]
perm [] = [[]]
perm (x:xs) = [(y:zs) | (y,ys) <- del (x:xs), zs <- perm ys]
--deleting duplicates
del :: [t] -> [(t,[t])]
del [] = []
del (x:xs) = ((x,xs) : [ (y,(x:ys)) | (y,ys) <- del xs ])
main :: IO()
main = do
print answer
解决方案的灵感来自:http://www.dcs.gla.ac.uk/mail-www/haskell/msg01929.html
答案 0 :(得分:1)
主要问题是perm digits
仅返回长度为10的列表,但list@[s,e,n,d,m,o,r,y] <- perm
位数要求列表长度为8.这会导致模式匹配失败。
模式匹配失败在列表推导中是静默的 - 它们对过滤输入很有用(指定你只关心匹配),这有时会引起问题。
快速解决方法可能是使用[ [s,e,n,d,m,o,r,y] | list@[s,e,n,d,m,o,r,y,_,_] <- perm digits, ... ]
代替。
其他一些建议:
expand'
和expand''
替换为一个expand
。您似乎将此作为学习经历,所以我只是给您一个提示:expand [s,e,n,d] + expand [m,o,r,e] == expand [m,o,n,e,y]
del
有点具有欺骗性的名字。它不会删除任何内容,只会创建(x_j, [x_0,...,x_{j-1},x_{j+1},...x_{n-1}])
长度列表n
[x_0,...,x_{n-1}]
perm k [1..n]
返回了k
个不同元素的所有排列[1..n]
。如果您想生成所有解决方案,这可能会有所帮助。