【发布时间】:2015-03-09 04:58:48
【问题描述】:
我一直在解决一些关于 Haskell 的组合问题,所以我写下了这两个函数:
permutations :: (Eq a) => [a] -> [[a]]
permutations [] = [[]]
permutations list = do
x <- list
xs <- permutations (filter (/= x) list)
return (x : xs)
combinations :: (Eq a, Ord a) => Int -> [a] -> [[a]]
combinations 0 _ = [[]]
combinations n list = do
x <- list
xs <- combinations (n-1) (filter (> x) list)
return (x : xs)
其工作原理如下:
*Main> permutations [1,2,3]
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
*Main> combinations 2 [1,2,3,4]
[[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
它们非常相似,所以我不得不对其进行抽象。我写了以下抽象:
combinatoric next [] = [[]]
combinatoric next list = do
x <- list
xs <- combinatoric next (next x list)
return (x : xs)
它接收一个控制如何过滤列表元素的函数。它可以用来轻松定义排列:
permutations :: (Eq a) => [a] -> [[a]]
permutations = combinatoric (\ x ls -> filter (/= x) ls)
但我无法以这种方式定义 combinations,因为它带有一个状态 (n)。我可以用一个额外的状态参数来扩展combinatoric,但这会变得太笨拙,我记得这种方法是不必要的in a somewhat similar situation。因此,我想知道:是否可以使用combinatorics 定义combinations?如果不是,那么combinatorics 的更好抽象是什么,它成功地包含了这两个函数?
【问题讨论】:
-
如果您不介意,您能解释一下
(filter (/= x) list)的工作原理吗?我看到x是list(根据上一行),您正在尝试从list中过滤不等于list的元素? -
permutations或combinations的良好实现可能不需要Eq或Ord实例,除非您尝试做一些更复杂的事情以便permuations [1,1] = [[1,1]]。跨度> -
@thefourtheye 不,这里
x只是列表的一个元素(1或2或3...)。这实际上是一种从列表中删除元素的肮脏和错误的方法,即filter (/= 2) [1,2,3,4] == [1,3,4]。我相信有更好的选择。请注意,实现了列表的 monad 实例,以便x <- list导致x不确定地成为list的每个元素,就好像该行将程序拆分为不同的宇宙一样。 -
@Viclib 那么,
x <- list将迭代list并每次都给x一个来自list的新值? -
@thefourtheye 是的,这就是 list monad 所做的。在 ghci 上试试这个:
do { x <- [1,2]; y <- [3,4]; return (x,y) }。结果是:[(1,3),(1,4),(2,3),(2,4)].
标签: algorithm haskell functional-programming