Haskell:避免使用if进行排列?

时间:2014-04-23 00:16:46

标签: haskell

我试图想出一个"单线"用于在Haskell中生成列表的排列。这就是我到目前为止所做的:

perms xs = if length xs == 0 then [[]] else [x:ys | x <- xs, ys <- perms $ delete x xs]

问题在于我不得不使用我在Haskell中非常不喜欢的if。是否可以避免使用if,多部分定义或案例陈述等,而且只能使用&#34;更高阶&#34;功能(例如foldr等)来实现这一目标? (并且理想情况下保持相对较小的单线)

4 个答案:

答案 0 :(得分:7)

如果您发现在没有对该功能进行任何有趣更改的情况下摆脱if令人满意,base-4.7.0.0(与GHC 7.8捆绑在一起)包含Data.Bool中的bool

perms xs = bool [[]] [x:ys | x <- xs, ys <- perms $ delete x xs] $ not (null xs)

答案 1 :(得分:4)

我设法使用perms来实现此foldr,但它变得更加复杂。很难相信这就是你要找的东西:

perms xs = filter (\l -> length l == length xs) $ foldr step [[]] xs
    where step x acc = (map (x:) . perms $ delete x xs) ++ acc

答案 2 :(得分:2)

[ghci] let perms1 xs = [x:ys | x <- xs, (not . null)  xs ,ys <- perms $ delete x xs]
[ghci] perms1 []
[]
[ghci] perms1 [1,2,3]
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

答案 3 :(得分:0)

您需要的更高功能是与if表达式相同的功能:检查给定谓词,如果为true,则计算为expression1,否则计算为expression2。

我在标准库中找不到这个,但这是你正在寻找的功能:

myBranchFunction :: t -> t -> [a] -> t
myBranchFunction e1 e2 xs = if length xs == 0 then e1 else e2

(如果您愿意,可以将length作为myBranchFunction的参数来进一步概括。)

然后你可以这样定义perms'

perms' :: Eq a => [a] -> [[a]]
perms' xs = myBranchFunction [[]] [x:ys | x <- xs, ys <- perms $ delete x xs] xs

请注意,我们所做的只是将if表达式移到另一个函数中。但是,对于这个函数,我想我宁愿不尝试将它放在一行上,只是使用case表达式来提高可读性。