Skip to content

Commit ea94999

Browse files
committed
feat: Add GHCi helper to create typed references to columns.
Fixes #40
1 parent 58b9936 commit ea94999

3 files changed

Lines changed: 45 additions & 1 deletion

File tree

.ghci

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
:set -XOverloadedStrings
22
:set -XTypeApplications
3+
:set -XTemplateHaskell
34

45
import qualified Data.Text as Str
56

67
default (Int, Str.Text, Double)
78

9+
:def! cols \s -> return ("_ = (); declareColumns " ++ s)

dataframe.cabal

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ library
5959
hashable >= 1.2 && <= 1.5.0.0,
6060
snappy >= 0.2.0.0 && <= 0.2.0.4,
6161
statistics >= 0.16.2.1 && <= 0.16.3.0,
62+
template-haskell >= 2.0 && <= 2.30,
6263
text >= 2.0 && <= 2.1.2,
6364
time >= 1.12 && <= 1.14,
6465
vector ^>= 0.13,
@@ -102,6 +103,7 @@ executable chipotle
102103
hashable >= 1.2 && <= 1.5.0.0,
103104
snappy >= 0.2.0.0 && <= 0.2.0.4,
104105
statistics >= 0.16.2.1 && <= 0.16.3.0,
106+
template-haskell >= 2.0 && <= 2.30,
105107
text >= 2.0 && <= 2.1.2,
106108
time >= 1.12 && <= 1.14,
107109
vector ^>= 0.13,
@@ -146,6 +148,7 @@ executable california_housing
146148
hashable >= 1.2 && <= 1.5.0.0,
147149
snappy >= 0.2.0.0 && <= 0.2.0.4,
148150
statistics >= 0.16.2.1 && <= 0.16.3.0,
151+
template-haskell >= 2.0 && <= 2.30,
149152
text >= 2.0 && <= 2.1.2,
150153
time >= 1.12 && <= 1.14,
151154
vector ^>= 0.13,
@@ -190,6 +193,7 @@ executable one_billion_row_challenge
190193
hashable >= 1.2 && <= 1.5.0.0,
191194
snappy >= 0.2.0.0 && <= 0.2.0.4,
192195
statistics >= 0.16.2.1 && <= 0.16.3.0,
196+
template-haskell >= 2.0 && <= 2.30,
193197
text >= 2.0 && <= 2.1.2,
194198
time >= 1.12 && <= 1.14,
195199
vector ^>= 0.13,
@@ -235,6 +239,7 @@ executable dataframe
235239
random >= 1 && <= 1.3.1,
236240
snappy >= 0.2.0.0 && <= 0.2.0.4,
237241
statistics >= 0.16.2.1 && <= 0.16.3.0,
242+
template-haskell >= 2.0 && <= 2.30,
238243
text >= 2.0 && <= 2.1.2,
239244
time >= 1.12 && <= 1.14,
240245
vector ^>= 0.13,

src/DataFrame/Functions.hs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,23 @@
1010
{-# LANGUAGE UndecidableInstances #-}
1111
{-# LANGUAGE MultiParamTypeClasses #-}
1212
{-# LANGUAGE BangPatterns #-}
13+
{-# LANGUAGE TemplateHaskell #-}
1314
module DataFrame.Functions where
1415

15-
import DataFrame.Internal.Column (Columnable)
16+
import DataFrame.Internal.Column
17+
import DataFrame.Internal.DataFrame (DataFrame(..), unsafeGetColumn)
1618
import DataFrame.Internal.Expression (Expr(..), UExpr(..))
1719

20+
import Control.Monad
21+
import Data.Function
22+
import qualified Data.List as L
23+
import qualified Data.Map as M
1824
import qualified Data.Text as T
1925
import qualified Data.Vector.Generic as VG
2026
import qualified Data.Vector.Unboxed as VU
27+
import qualified Data.Vector as VB
28+
import Language.Haskell.TH
29+
import qualified Language.Haskell.TH.Syntax as TH
2130

2231
col :: Columnable a => T.Text -> Expr a
2332
col = Col
@@ -68,3 +77,31 @@ mean (Col name) = let
6877
(!total, !n) = VG.foldl' (\(!total, !n) v -> (total + v, n + 1)) (0 :: Double, 0 :: Int) samp
6978
in total / fromIntegral n
7079
in NumericAggregate name "mean" mean'
80+
81+
-- TODO: Enumerate universe of primitives.
82+
-- Maybe this should go in a separate module where people can add their
83+
-- universe of types.
84+
-- Or maybe make it easier to insert your on types here.
85+
typeFromString :: String -> Q Type
86+
typeFromString s = case s of
87+
"Int" -> [t| Int |]
88+
"Double" -> [t| Double |]
89+
"Bool" -> [t| Bool |]
90+
"Text" -> [t| T.Text |]
91+
"Maybe Int" -> [t| Maybe Int |]
92+
"Maybe Double" -> [t| Maybe Double |]
93+
"Maybe Bool" -> [t| Maybe Bool |]
94+
"Maybe Text" -> [t| Maybe T.Text |]
95+
_ -> fail $ "Unsupported type: " ++ s
96+
97+
declareColumns :: DataFrame -> DecsQ
98+
declareColumns df = let
99+
names = (map fst . L.sortBy (compare `on` snd). M.toList . columnIndices) df
100+
types = map (columnTypeString . (`unsafeGetColumn` df)) names
101+
specs = zip names types
102+
in fmap concat $ forM specs $ \(nm, tyStr) -> do
103+
ty <- typeFromString tyStr
104+
let n = mkName (T.unpack nm)
105+
sig <- sigD n [t| Expr $(pure ty) |]
106+
val <- valD (varP n) (normalB [| col $(TH.lift nm) |]) []
107+
pure [sig, val]

0 commit comments

Comments
 (0)