diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 # Revision history for dataframe
 
+## 0.3.1.2
+* Update granite version, again, for stackage.
+
 ## 0.3.1.1
 * Aggregation now works on expressions rather than just column references.
 * Export writeCsv
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,37 +1,27 @@
-{-# LANGUAGE NumericUnderscores #-}
 -- Useful Haskell extensions.
 -- Allow string literal to be interpreted as any other string type.
+
 {-# LANGUAGE OverloadedStrings #-}
 
 import qualified DataFrame as D -- import for general functionality.
-import Data.Time
-import qualified Data.Vector.Unboxed as VU
-import System.Random.Stateful
+import qualified DataFrame.Functions as F
+import DataFrame ((|>))
 
+import Data.Function
+import qualified Data.List as L
+import Data.Maybe
+import System.Environment
+
 main :: IO ()
 main = do
-    let n = 100_000_000
-    g <- newIOGenM =<< newStdGen
-    let range = (-20.0 :: Double, 20.0 :: Double)
-    startGeneration <- getCurrentTime
-    ns <- VU.replicateM n (uniformRM range g)
-    xs <- VU.replicateM n (uniformRM range g)
-    ys <- VU.replicateM n (uniformRM range g)
-    let df = D.fromUnnamedColumns (map D.fromUnboxedVector [ns, xs, ys])
-    endGeneration <- getCurrentTime
-    let generationTime = diffUTCTime endGeneration startGeneration
-    putStrLn $ "Data generation Time: " ++ show generationTime
-    startCalculation <- getCurrentTime
-    print $ D.mean "0" df
-    print $ D.variance "1" df
-    print $ D.correlation "1" "2" df
-    endCalculation <- getCurrentTime
-    let calculationTime = diffUTCTime endCalculation startCalculation
-    putStrLn $ "Calculation Time: " ++ show calculationTime
-    startFilter <- getCurrentTime
-    print $ D.filter "0" (>= (19.9 :: Double)) df D.|> D.take 10
-    endFilter <- getCurrentTime
-    let filterTime = diffUTCTime endFilter startFilter
-    putStrLn $ "Filter Time: " ++ show filterTime
-    let totalTime = diffUTCTime endFilter startGeneration
-    putStrLn $ "Total Time: " ++ show totalTime
+    (d:b:_) <- fmap (map read) getArgs
+    df <- D.readCsv "./data/housing.csv"
+    let (Right e) = F.synthesizeFeatureExpr "median_house_value" d b (df |> D.exclude ["ocean_proximity", "total_bedrooms", "median_income"])
+
+    print e
+
+    mapM_ print (L.sortBy (flip compare `on` snd) (correlations (df  |> D.derive "n" e)))
+
+correlations d = map (`correlationWithHouseValue` d) (D.columnNames d)
+    where
+        correlationWithHouseValue columnName d = (columnName, fromMaybe 0 (D.correlation columnName "median_house_value" d))
diff --git a/dataframe.cabal b/dataframe.cabal
--- a/dataframe.cabal
+++ b/dataframe.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               dataframe
-version:            0.3.1.1
+version:            0.3.1.2
 
 synopsis: A fast, safe, and intuitive DataFrame library.
 
@@ -75,7 +75,7 @@
                       bytestring-lexing >= 0.5 && < 0.6,
                       containers >= 0.6.7 && < 0.8,
                       directory >= 1.3.0.0 && < 2,
-                      granite ^>= 0.2,
+                      granite ^>= 0.3,
                       hashable >= 1.2 && < 2,
                       process ^>= 1.6,
                       snappy-hs ^>= 0.1,
diff --git a/src/DataFrame/Functions.hs b/src/DataFrame/Functions.hs
--- a/src/DataFrame/Functions.hs
+++ b/src/DataFrame/Functions.hs
@@ -97,6 +97,12 @@
 mean :: (Columnable a, Real a, VU.Unbox a) => Expr a -> Expr Double
 mean expr = AggNumericVector expr "mean" mean'
 
+median :: Expr Double -> Expr Double
+median expr = AggNumericVector expr "mean" median'
+
+percentile :: Int -> Expr Double -> Expr Double
+percentile n expr = AggNumericVector expr (T.pack $ "percentile " ++ show n) ((VU.! 0) . quantiles' (VU.fromList [n]) 100)
+
 standardDeviation :: (Columnable a, Real a, VU.Unbox a) => Expr a -> Expr Double
 standardDeviation expr = AggNumericVector expr "stddev" (sqrt . variance')
 
@@ -117,6 +123,11 @@
     | (i, p) <- zip [0..] existingPrograms
     , (j, q) <- zip [0..] existingPrograms
     , i Prelude.>= j
+    ] ++
+    [ ifThenElse (p DataFrame.Functions.>= percentile n p) p q
+    | p <- existingPrograms
+    , q <- existingPrograms ++ [lit 1, lit 0, lit (-1)]
+    , n <- [1, 25, 50, 75, 99]
     ] ++
     [ p - q
     | p <- existingPrograms
diff --git a/src/DataFrame/Internal/Expression.hs b/src/DataFrame/Internal/Expression.hs
--- a/src/DataFrame/Internal/Expression.hs
+++ b/src/DataFrame/Internal/Expression.hs
@@ -484,7 +484,7 @@
     show :: forall a. (Show a) => Expr a -> String
     show (Col name) = "(col @" ++ show (typeRep @a) ++ " " ++ show name ++ ")"
     show (Lit value) = show value
-    show (If cond l r) = "(ifThenElse " ++ show l ++ " " ++ show r ++ ")"
+    show (If cond l r) = "(ifThenElse " ++ show cond ++ " " ++ show l ++ " " ++ show r ++ ")"
     show (UnaryOp name f value) = "(" ++ T.unpack name ++ " " ++ show value ++ ")"
     show (BinaryOp name f a b) = "(" ++ T.unpack name ++ " " ++ show a ++ " " ++ show b ++ ")"
     show (AggNumericVector expr op _) = "(" ++ T.unpack op ++ " " ++ show expr ++ ")"
diff --git a/src/DataFrame/Internal/Statistics.hs b/src/DataFrame/Internal/Statistics.hs
--- a/src/DataFrame/Internal/Statistics.hs
+++ b/src/DataFrame/Internal/Statistics.hs
@@ -15,7 +15,7 @@
 mean' samp = VU.sum (VU.map realToFrac samp) / fromIntegral (VU.length samp)
 {-# INLINE mean' #-}
 
-median' :: VU.Vector Double -> Double
+median' :: (Real a, VU.Unbox a) => VU.Vector a -> Double
 median' samp
     | VU.null samp = throw $ EmptyDataSetException "median"
     | otherwise = runST $ do
@@ -25,10 +25,10 @@
             middleIndex = len `div` 2
         middleElement <- VUM.read mutableSamp middleIndex
         if odd len
-            then pure middleElement
+            then pure (realToFrac middleElement)
             else do
                 prev <- VUM.read mutableSamp (middleIndex - 1)
-                pure ((middleElement + prev) / 2)
+                pure (realToFrac (middleElement + prev) / 2)
 {-# INLINE median' #-}
 
 -- accumulator: count, mean, m2
diff --git a/tests/Operations/Statistics.hs b/tests/Operations/Statistics.hs
--- a/tests/Operations/Statistics.hs
+++ b/tests/Operations/Statistics.hs
@@ -16,7 +16,7 @@
     TestCase
         ( assertEqual
             "Median of an odd length data set"
-            (D.median' (VU.fromList [179.94, 231.94, 839.06, 534.23, 248.94]))
+            (D.median' (VU.fromList @Double [179.94, 231.94, 839.06, 534.23, 248.94]))
             248.94
         )
 
@@ -25,7 +25,7 @@
     TestCase
         ( assertEqual
             "Median of an even length data set"
-            (D.median' (VU.fromList [179.94, 231.94, 839.06, 534.23, 248.94, 276.37]))
+            (D.median' (VU.fromList @Double [179.94, 231.94, 839.06, 534.23, 248.94, 276.37]))
             262.655
         )
 
@@ -35,7 +35,7 @@
         ( assertExpectException
             "[Error Case]"
             (D.emptyDataSetError "median")
-            (print $ D.median' (VU.fromList []))
+            (print $ D.median' (VU.fromList @Double []))
         )
 
 skewnessOfDataSetWithSameElements :: Test
