> {-# LANGUAGE TypeOperators, FlexibleContexts, UndecidableInstances #-}
> import Data.Reflection
> import Data.List (sort)
> myList = [1,2,5,4,2]
> newtype (s `Ordered` a) = Ordered { getOrdered :: a }
> instance (s `Reflects` (a -> a -> Ordering)) => Eq (s `Ordered` a) where
> a == b = (a `compare` b) == EQ
> instance (s `Reflects` (a -> a -> Ordering)) => Ord (s `Ordered` a) where
> a `compare` b = reflect (undefined `asReifiedComparison` a)
> (getOrdered a) (getOrdered b)
> where
> asReifiedComparison :: s -> (s `Ordered` a) -> s
> asReifiedComparison = const
-- for expository purposes, I renamed your sort, 'mySort' and aped it with the Data.List sort
> mySort :: Ord a => [a] -> IO [a]
> mySort = return . sort
> withOrder :: s -> a -> s `Ordered` a
> withOrder = const Ordered
> mySortBy :: (a -> a -> Ordering) -> [a] -> IO [a]
> mySortBy f as = reify f (\s -> map getOrdered `fmap` mySort (map (withOrder s) as))
> test1 = mySortBy compare myList
> test2 = mySortBy (flip compare) myList
*Main> test1
Loading package reflection-0.1.1 ... linking ... done.
[1,2,2,4,5]
*Main> test2
[5,4,2,2,1]
The sort function is lifted up to the type level by 'reify' and is extracted uniformly by 'reflect' eliminating the bias or your first proposed implementation. Note that the mapping of withOrder is just to force them all to agree on the type parameter s.
-Edward Kmett