Haskell中的口头算术(SEND + MORE = MONEY)

时间:2016-01-30 21:59:48

标签: haskell functional-programming

我正在尝试在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

1 个答案:

答案 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版本,它带有另一个参数来指定排列中元素的数量,因此perm k [1..n]返回了k个不同元素的所有排列[1..n]。如果您想生成所有解决方案,这可能会有所帮助。