基于条件对列表进行分区的函数 - Haskell

Fun*_*zer 4 haskell

我正在学习 Haskell,我正在做的一个练习是创建一个函数,该函数根据函数的返回值将列表划分为三个列表,以便为等于 1 的函数值获得第一个子列表,函数值的第二个子列表为 2,第三个子列表包含其他所有内容。

函数声明读取

partition3 :: (a -> Int) -> [a] -> ([a], [a], [a])
partition3 _ [] = []
Run Code Online (Sandbox Code Playgroud)

作为入门示例,请考虑

partition3 (\x -> mod x 5) [1..10] = ([1,6], [2,7], [3,4,5,8,9,10])
Run Code Online (Sandbox Code Playgroud)

现在,我已经对函数filterAny, isSuitable, removeIf,进行了编码isNotSuitable。完整代码如下:

filterAny :: [a -> Bool] -> [a] -> [a]
filterAny _ [] = []
filterAny ps (x:xs)
  | isSuitable ps x = x : filterAny ps xs
  | otherwise = filterAny ps xs

isSuitable :: [a -> Bool] -> a -> Bool
isSuitable [] _ = False
isSuitable (p:ps) v
  | p v       = True
  | otherwise = isSuitable ps v

removeIf :: [a -> Bool] -> [a] -> [a]
removeIf _ [] = []
removeIf ps (x:xs)
  | isNotSuitable ps x = x : removeIf ps xs
  | otherwise = removeIf ps xs

isNotSuitable :: [a -> Bool] -> a -> Bool
isNotSuitable [] _ = True
isNotSuitable (p:ps) v
  | p v       = False
  | otherwise = isNotSuitable ps v
Run Code Online (Sandbox Code Playgroud)

使用这些函数,我们可以获得所需的输出partition3

filterAny [(\x -> mod x 5 == 1)] [1..10] = [1,6]
filterAny [(\x -> mod x 5 == 2)] [1..10] = [2,7]
removeIf [even, (\x -> x > 5)] [1..10] = [3,4,5,8,9,10]
Run Code Online (Sandbox Code Playgroud)

不幸的是,我仍然没有想出如何编写这个函数来输出 ([1,6], [2,7], [3,4,5,8,9,10])

Jus*_* L. 5

考虑“创建”类似类型值的一种高级方法(a,b,c)是考虑必须“构造”它的方式,例如构造函数。在这种情况下,(a,b,c)有一个构造函数(_,_,_). 所以你需要考虑要放在第一个位置的东西,要放在第二个位置的东西,以及要放在第三个位置的东西……你就完成了。

所以让我们像这样概述我们的功能:

partition3 :: (a -> Int) -> [a] -> ([a], [a], [a])
partition3 f xs = (_, _, _)
Run Code Online (Sandbox Code Playgroud)

我们知道我们的最终答案是形式(_,_,_),其中“空白”包含我们想要放入元组中的每个项目。让我们给每个空白起一个有用的名字。

partition3 :: (a -> Int) -> [a] -> ([a], [a], [a])
partition3 f xs = (equalsOne, equalsTwo, theRest)
  where
    equalsOne = ???
    equalsTwo = ???
    theRest   = ???
Run Code Online (Sandbox Code Playgroud)

现在你只需要equalsOne成为与xs你想要的属性相匹配的项目,等等。属性equalsOne是“一个值x匹配,当你应用f它时,它给出1”。所以让我们写下使用filterAny

partition3 :: (a -> Int) -> [a] -> ([a], [a], [a])
partition3 f xs = (equalsOne, equalsTwo, theRest)
  where
    equalsOne = filterAny [\x -> f x == 1] xs
    equalsTwo = ???
    theRest   = ???
Run Code Online (Sandbox Code Playgroud)

在这里,我们过滤xs任何项目,如果您申请f它,则给出1.

你能想出实现equalsTwo和的方法theRest吗?