4

Does there exist a point-free function for filter function to find minimum of first element of pair in a list? for example:

findMinimum xs =  filter ((== minimum (map fst xs)) . fst ) xs

-- example:
findMinimum [(0, 0), (0, 1), (2, 2), (3, 2), (1, 4)] = [(0, 0), (0, 1)]

How to convert findMinimum function to point-free:

findMinimum = ??
Will Ness
  • 70,110
  • 9
  • 98
  • 181
JoeChoi
  • 395
  • 1
  • 9
  • 4
    Every function can be written in point-free form; the question is, does the point-free form read better than a pointed equivalent? – chepner Dec 19 '18 at 18:50

3 Answers3

6

pointfree.io outputs this, which is not too bad. I still prefer the original code, though.

findMinimum = filter =<< (. fst) . (==) . minimum . map fst
chi
  • 111,837
  • 3
  • 133
  • 218
  • Yes, this is not too bad, I prefer point-free version and vote it up. Does exist more readable answer? – JoeChoi Dec 19 '18 at 19:01
  • @JoeChoi I don't think there's anything much better since you have two occurrences of `xs`, so one needs something like `>>=` or `<*>` to "duplicate" the implicit argument. Using `<*>` seems to lead to worse code, IMO. – chi Dec 19 '18 at 19:06
  • 1
    @JoeChoi maybe just use the optional parens, `filter =<< ((. fst) . (==) . minimum . map fst)`, to make the grouping more visually apparent. – Will Ness Dec 20 '18 at 09:22
4

a different implementation

head . groupBy ((==) `on` fst) . sortOn fst

sort and group by first, pick the first sub list. Perhaps you may want to handle empty list explicitly.

karakfa
  • 66,216
  • 7
  • 41
  • 56
  • 1
    Of course, this replaces a pair of O(n) traversals with an O(n lg n) sort. – chepner Dec 19 '18 at 21:06
  • 1
    Great answer, thank you. I modify it a little bit for my need to handle empty list: `concat . take 1 . groupBy ((==) `on` fst) . sortOn fst`. It desired as accepted answer. – JoeChoi Dec 20 '18 at 04:13
  • I don’t think it’s O(n log n) (using O informally). – augustss Dec 21 '18 at 04:38
2

Putting the pair in Arg, you get ordering on the first element, that you can exploit as follows:

import Data.Semigroup (Arg(..))
import Data.Ord (comparing)

findMinimum :: Ord a => [(a, b)] -> (a, b)
findMinimum = minimumBy (comparing (uncurry Arg))
Li-yao Xia
  • 31,896
  • 2
  • 33
  • 56
  • Thank you. I vote up for `comparing (uncurry Arg)` to provide another way to do that as `comparing fst`. But `findMinimum` return list of pair as `[(a,b)]` rather than `(a, b)`. – JoeChoi Dec 20 '18 at 06:10