Haskell already has an Ord
instance for pairs of elements that each have Ord
instances, but the instance for pairs compares the first elements before the second. One solution that was already posted is to use minimumBy
and supply your own comparing function, but another is to use swap
liberally:
import Data.Tuple (swap)
myMin :: (Ord a, Ord b) => [(a, b)] -> (a, b)
myMin = swap . minimum . fmap swap
If you're super concerned about performance, you might be worried that we're traversing the list twice. One way to address this is to use coerce
to do a type-safe coercion rather than fmap
ing swap
, but that means we need a data type that is coercible to (a,b)
. If you're doing a lot of these comparisons, you could consider creating:
newtype Swap a b = Swap { getSwap :: (a,b) }
deriving(Eq)
instance (Ord a, Ord b) => Ord (Swap a b) where
compare (Swap (a, b)) (Swap (c, d)) = compare (b,a) (d,c)
With this, you can then write myMin
as:
{-# LANGUAGE TypeApplications #-}
import Data.Coerce (coerce)
myMin :: (Ord a, Ord b) => [(a, b)] -> (a, b)
myMin = getSwap . minimum @[] . coerce
(Note that because minimum
is polymorphic over the container type and we're using coerce
, we need to tell GHC which type of container we're using. Thus, we use the type application @[]
after minimum
.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…