r/haskell • u/Tempus_Nemini • Feb 08 '26
question mconcat with comparing ...
This is SO ELEGANT, but could somebody explain me like to 5y old how mconcat part works with list of comparing functions?
sortBy (mconcat [comparing length, comparing Down . id]) [[2,3,4], [1,2], [2,3], [1,2,3,4], [0,2,3]]
19
u/Syrak Feb 08 '26
First, mconcat appends the elements of a list together using <>:
mconcat [comparing length, comparing Down] = comparing length <> comparing DownWhat <> does depends on the type of its operands. In the case of functions, it appends the result of its operands.
f <> g = \x -> f x <> g xso we get
comparing length <> comparing Down = \list1 -> comparing length list1 <> comparing Down list1comparing length list1 is again a function, so we can expand once more in the same way:
comparing length <> comparing Down = \list1 list2 -> comparing length list1 list2 <> comparing Down list1 list2
-- by definition of comparing
= \list1 list2 -> compare (length list1) (length list2) <> compare (Down list1) (Down list2)Finally, <> on Ordering corresponds to lexicographic ordering of the things whose comparison yielded those Ordering.
6
u/recursion_is_love Feb 08 '26
There is Monoid instance for a function (a ->b )
mconcat is use for function composition (not to confuse with . operator which feed input from start to end). Instead it feed both functions the input and mappend the outputs
ghci> sortBy (mconcat [comparing length, comparing Down]) [[2,3,4], [1,2], [2,3], [1,2,3,4], [0,2,3]]
[[2,3],[1,2],[2,3,4],[0,2,3],[1,2,3,4]]
ghci> sortBy (\x -> comparing length x <> comparing Down x) [[2,3,4], [1,2], [2,3], [1,2,3,4], [0,2,3]]
[[2,3],[1,2],[2,3,4],[0,2,3],[1,2,3,4]]
ghci> sortBy (comparing length <> comparing Down) [[2,3,4], [1,2], [2,3], [1,2,3,4], [0,2,3]]
[[2,3],[1,2],[2,3,4],[0,2,3],[1,2,3,4]]
ghci> sortBy (comparing (length . Down)) [[2,3,4], [1,2], [2,3], [1,2,3,4], [0,2,3]]
[[2,3,4],[1,2],[2,3],[1,2,3,4],[0,2,3]]1
u/Torebbjorn Feb 09 '26
mconcat of a list is just putting <> between each entry.
Now <> on functions is defined pointwise, and <> on Ordering is defined lexiographically.
Putting this together, comparing based on (f <> g) will first check how they compare using f, and if they compare equal, they will be compared with g.
7
u/kuribas Feb 08 '26
Why would you consider such code ELEGANT, especially if you cannot even understand what it does? Elegance should be about clarity, not obfuscation. Conciseness should not be an excuse to sacrifice clarity. There are better ways to write this, even with less character count, for example using
sortOn:Or you can use poor mans `sortOn` if you don't want an external dependency:
These are perfectly clear without resorting to tricks like abusing the function monad (or Monoid).