```module Data.Pass.Robust
( Robust(..)
, median
, iqm
, idm
, tercile, t1, t2
, quartile, q1, q2, q3
, quintile, qu1, qu2, qu3, qu4
, percentile
, permille
) where

import Data.Pass.Type
import Data.Pass.Calc
import Data.Pass.Fun
import Data.Pass.Thrist
import Data.Pass.L
import Data.Pass.L.Estimator

-- | embedding for L-estimators
class Robust l where
robust :: L a b -> l a b

winsorized :: (Fractional b, Ord b) => Rational -> L a b -> l a b
winsorized p f = robust \$ Winsorized p f

trimmed :: (Fractional b, Ord b) => Rational -> L a b -> l a b
trimmed p f = robust \$ Trimmed p f

jackknifed :: (Fractional b, Ord b) => L a b -> l a b
jackknifed f = robust \$ Jackknifed f

lscale :: (Fractional a, Ord a) => l a a
lscale = robust LScale

quantile :: (Fractional a, Ord a) => Rational -> l a a
quantile p = robust \$ QuantileBy R2 p

midhinge :: (Fractional a, Ord a) => l a a
midhinge = robust \$ 0.5 :* (q1 :+ q3)

-- | Tukey's trimean
trimean :: (Fractional a, Ord a) => l a a
trimean = robust \$ 0.25 :* (q1 :+ 2 :* q2 :+ q3)

-- | interquartile range
iqr :: (Fractional a, Ord a) => l a a
iqr = robust \$ ((-1) :* q1) :+ q3

idr :: (Fractional a, Ord a) => l a a
idr = robust \$ ((-1) :* quantile 0.1) :+ quantile 0.9

-- | interquartile mean
iqm :: (Robust l, Fractional a, Ord a) => l a a
iqm = trimmed 0.25 LMean

idm :: (Robust l, Fractional a, Ord a) => l a a
idm = trimmed 0.1 LMean

median :: (Robust l, Fractional a, Ord a) => l a a
median = quantile 0.5

tercile :: (Robust l, Fractional a, Ord a) => Rational -> l a a
tercile n = quantile (n/3)

-- | terciles 1 and 2
t1, t2 :: (Robust l, Fractional a, Ord a) => l a a
t1 = tercile 1
t2 = tercile 2

quartile :: (Robust l, Fractional a, Ord a) => Rational -> l a a
quartile n = quantile (n/4)

-- | quantiles, with breakdown points 25%, 50%, and 25% respectively
q1, q2, q3 :: (Robust l, Fractional a, Ord a) => l a a
q1 = quantile 0.25
q2 = median
q3 = quantile 0.75

quintile :: (Robust l, Fractional a, Ord a) => Rational -> l a a
quintile n = quantile (n/5)

-- | quintiles 1 through 4
qu1, qu2, qu3, qu4 :: (Robust l, Fractional a, Ord a) => l a a
qu1 = quintile 1
qu2 = quintile 2
qu3 = quintile 3
qu4 = quintile 4

percentile :: (Robust l, Fractional a, Ord a) => Rational -> l a a
percentile n = quantile (n/100)

permille :: (Robust l, Fractional a, Ord a) => Rational -> l a a
permille n = quantile (n/1000)

instance Robust L where
robust = id

instance Robust l => Robust (Fun l) where
robust = Fun . robust

newtype Flip f a b = Flip { flop :: f b a }

instance Robust (Pass k) where
robust l = L id (flop (eqL l (Flip l))) (eqL l Nil)
midhinge = (q1 + q3) / 2
trimean  = (q1 + 2 * q2 + q3) / 4
iqr      = q3 - q1

instance Robust (Calc k) where
robust l = robust l :& Stop
midhinge = midhinge :& Stop
trimean  = trimean :& Stop
iqr      = iqr :& Stop
```