如何在Haskell中编写符合指定签名的groupBy函数?
Implementing
groupBy :: (a -> a -> Bool) -> [a] -> [[a]] for Equality or Strictly Increasing Subsequences Got it, let's work through implementing this custom groupBy function in Haskell. First, let's make sure we're all on the same page with the requirements:
- Function Signature: Must be exactly
groupBy :: (a -> a -> Bool) -> [a] -> [[a]] - Grouping Rules: The function should cluster elements based on the provided binary predicate:
- When using
(==)as the predicate, group consecutive equal elements together. - When using
(<)as the predicate, group consecutive elements that form a strictly increasing subsequence.
- When using
Example Usage
Let's start with the examples given to clarify expected behavior:
-- Grouping equal elements with (==) groupBy (==) [0, 0, 1, 1, 2, 2] == [[0, 0], [1, 1], [2, 2]] groupBy (==) [0, 1, 2] == [[0], [1], [2]] -- Grouping strictly increasing subsequences with (<) groupBy (<) [1,2,3,2,3,4,1] == [[1,2,3], [2,3,4], [1]] groupBy (<) [5,4,3,2,1] == [[5], [4], [3], [2], [1]]
The Implementation
Here's an efficient recursive implementation that meets all the requirements:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]] groupBy _ [] = [] groupBy p (x:xs) = go x [x] xs where go lastElem current [] = [current] go lastElem current (y:ys) | p lastElem y = go y (current ++ [y]) ys | otherwise = current : go y [y] ys
How It Works
Let's break down the logic step by step:
- Edge Case Handling: If the input list is empty, we just return an empty list—no groups to form.
- Initialization: For a non-empty list, we start our grouping process with the first element
xas the start of the first group, using the helper functiongo. - Helper Function
go:- It keeps track of three key things: the last element in the current group (
lastElem), the current group itself (current), and the remaining unprocessed elements of the list. - When there are no elements left to process, we wrap up by returning the current group as the final entry in our result.
- If the next element
ysatisfies the predicate withlastElem(e.g.,lastElem < yfor strictly increasing, orlastElem == yfor equality), we addyto the current group and keep processing the rest of the list. - If the predicate isn't satisfied, we finalize the current group, add it to our result, and start a new group with
yas the first element.
- It keeps track of three key things: the last element in the current group (
Testing It Out
Let's verify with one of the trickier examples:
- For
groupBy (<) [1,2,3,2,3,4,1]:- We start with
lastElem = 1,current = [1], remaining list[2,3,2,3,4,1] 1 < 2is true → update tolastElem = 2,current = [1,2], remaining[3,2,3,4,1]2 < 3is true → update tolastElem =3,current = [1,2,3], remaining[2,3,4,1]3 < 2is false → add[1,2,3]to results, start new group with2- Repeat the process for the remaining elements, ending up with
[[1,2,3], [2,3,4], [1]]—exactly what we expect!
- We start with
This implementation is flexible enough to work with any valid binary predicate, not just (==) and <, while sticking strictly to the required signature.
内容的提问来源于stack exchange,提问作者polebence
相关产品推荐
相关产品推荐

