我试图想出一个"单线"用于在Haskell中生成列表的排列。这就是我到目前为止所做的:
perms xs = if length xs == 0 then [[]] else [x:ys | x <- xs, ys <- perms $ delete x xs]
问题在于我不得不使用我在Haskell中非常不喜欢的if
。是否可以避免使用if
,多部分定义或案例陈述等,而且只能使用&#34;更高阶&#34;功能(例如foldr
等)来实现这一目标? (并且理想情况下保持相对较小的单线)
答案 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
表达式来提高可读性。