【发布时间】:2016-03-31 20:19:34
【问题描述】:
在this question,作者提出了一个有趣的编程问题:给定两个字符串,找出保留原始字符串顺序的那些可能的“交错”排列。
我将问题概括为n 字符串,而不是 OP 中的 2,并提出:
-- charCandidate is a function that finds possible character from given strings.
-- input : list of strings
-- output : a list of tuple, whose first value holds a character
-- and second value holds the rest of strings with that character removed
-- i.e ["ab", "cd"] -> [('a', ["b", "cd"])] ..
charCandidate xs = charCandidate' xs []
charCandidate' :: [String] -> [String] -> [(Char, [String])]
charCandidate' [] _ = []
charCandidate' ([]:xs) prev =
charCandidate' xs prev
charCandidate' (x@(c:rest):xs) prev =
(c, prev ++ [rest] ++ xs) : charCandidate' xs (x:prev)
interleavings :: [String] -> [String]
interleavings xs = interleavings' xs []
-- interleavings is a function that repeatedly applies 'charCandidate' function, to consume
-- the tuple and build permutations.
-- stops looping if there is no more tuple from charCandidate.
interleavings' :: [String] -> String -> [String]
interleavings' xs prev =
let candidates = charCandidate xs
in case candidates of
[] -> [prev]
_ -> concat . map (\(char, ys) -> interleavings' ys (prev ++ [char])) $ candidates
-- test case
input :: [String]
input = ["ab", "cd"]
-- interleavings input == ["abcd","acbd","acdb","cabd","cadb","cdab"]
它可以工作,但是我很关心代码:
- 太丑了。没有积分!
- 显式递归和附加函数参数
prev以保留状态 - 使用元组作为中间形式
如何将上述程序重写为更“haskellic”、简洁、易读和更符合“函数式编程”?
【问题讨论】:
-
我不建议过分追求无点风格。它可能具有教育意义,甚至很有趣,但如果超出某个点,无点编程会使事情的可读性降低,而不是更多......
-
另外,请避免使用
(:) (...) $ ...之类的东西,转而使用(...):(...)。在上述情况下,您甚至不需要第二组括号... -
我没有测试过,但我怀疑你的意思是在你目前有
getCandidate的任何地方写charCandidate',并打算在你目前有charCandidate的任何地方写charCandidate'在五行在charCandidate'的类型声明之后。 -
@DanielWagner 抱歉,我在从编辑器复制粘贴时更改了一些名称,似乎我忘记让我的编辑与名称更改匹配。
标签: haskell functional-programming