Skip to content

Commit 18c1aa1

Browse files
committed
First version
1 parent 72bfe17 commit 18c1aa1

File tree

6 files changed

+204
-0
lines changed

6 files changed

+204
-0
lines changed

.purs-repl

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import Prelude

bower.json

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "purescript-dplyr",
3+
"ignore": [
4+
"**/.*",
5+
"node_modules",
6+
"bower_components",
7+
"output"
8+
],
9+
"dependencies": {
10+
"purescript-prelude": "^4.0.1",
11+
"purescript-console": "^4.1.0",
12+
"purescript-effect": "^2.0.0",
13+
"purescript-transformers": "^4.1.0",
14+
"purescript-newtype": "^3.0.0",
15+
"purescript-lists": "^5.0.0",
16+
"purescript-generics-rep": "^6.0.0",
17+
"purescript-filterable": "^3.0.1",
18+
"purescript-record": "^1.0.0",
19+
"purescript-record-extra": "^1.0.0"
20+
},
21+
"devDependencies": {
22+
"purescript-psci-support": "^4.0.0"
23+
}
24+
}

src/Data/DataFrame.purs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module Data.DataFrame where
2+
3+
import Prelude
4+
5+
import Data.Compactable (class Compactable, separate)
6+
import Data.Filterable (class Filterable, partitionMap)
7+
import Data.Generic.Rep (class Generic)
8+
import Data.List (catMaybes, mapMaybe, partition)
9+
import Data.List (filter) as List
10+
import Data.List.Types (List)
11+
import Data.Newtype (class Newtype, over, unwrap, wrap)
12+
13+
newtype DataFrame a = DataFrame (List a)
14+
15+
derive instance newtypeDF :: Newtype (DataFrame a) _
16+
17+
derive instance genericDF :: Generic (DataFrame a) _
18+
19+
derive instance functorDF :: Functor DataFrame
20+
21+
instance semigroupDF :: Semigroup (DataFrame a) where
22+
append (DataFrame l1) (DataFrame l2) = wrap $ append l1 l2
23+
24+
instance monoidDF :: Monoid (DataFrame a) where
25+
mempty = wrap mempty
26+
27+
instance compactbleDF :: Compactable DataFrame where
28+
compact = over DataFrame catMaybes
29+
separate = (\{left, right} -> {left: wrap left, right: wrap right}) <<< separate <<< unwrap
30+
31+
instance filterableDF :: Filterable DataFrame where
32+
filter f = over DataFrame (List.filter f)
33+
filterMap f = over DataFrame (mapMaybe f)
34+
partition f = (\{yes, no} -> {yes: wrap yes, no: wrap no}) <<< partition f <<< unwrap
35+
partitionMap f = (\{left, right} -> {left: wrap left, right: wrap right}) <<< partitionMap f <<< unwrap

src/Data/Query.purs

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
module Data.Query where
2+
3+
import Prelude
4+
5+
import Control.Monad.Reader.Class (ask)
6+
import Control.Monad.Reader.Trans (ReaderT)
7+
import Data.DataFrame (DataFrame(..))
8+
import Data.Filterable (filter) as Filterable
9+
import Data.Function (on)
10+
import Data.List (sortBy)
11+
import Data.List.Lazy (List, uncons, (:))
12+
import Data.List.Lazy (filter) as L
13+
import Data.Maybe (maybe)
14+
import Data.Newtype (over)
15+
import Data.Ordering (invert)
16+
import Data.Symbol (class IsSymbol, SProxy(..))
17+
import Prim.Row (class Cons, class Lacks)
18+
import Prim.RowList (class RowToList, Cons, Nil, kind RowList)
19+
import Record (get, insert)
20+
import Record (insert, rename) as R
21+
import Type.Row (class ListToRow, RLProxy(..), RProxy)
22+
23+
type Query m a b = ReaderT (DataFrame a) m (DataFrame b)
24+
25+
filter :: m a. Monad m => (a -> Boolean) -> Query m a a
26+
filter f = (Filterable.filter f) <$> ask
27+
28+
arrange
29+
:: m sym a rec without
30+
. Ord a
31+
=> Monad m
32+
=> IsSymbol sym
33+
=> Lacks sym without
34+
=> Cons sym a without rec
35+
=> SProxy sym
36+
-> Boolean
37+
-> Query m ({|rec}) ({|rec})
38+
arrange proxy asc = (over DataFrame $ sortBy (comp `on` (get proxy))) <$> ask
39+
where
40+
comp :: a -> a -> Ordering
41+
comp a = if asc then compare a else invert <<< compare a
42+
43+
pull
44+
:: m sym a rec without' without
45+
. Monad m
46+
=> IsSymbol sym
47+
=> Lacks sym without
48+
=> Lacks sym without'
49+
=> Cons sym a without rec
50+
=> SProxy sym
51+
-> Query m {|rec} a
52+
pull proxy = (over DataFrame $ map (( get proxy))) <$> ask
53+
54+
class RowSubset (row :: # Type) (xs :: RowList) (subrow :: # Type) | row xs -> subrow where
55+
subsetImpl :: RLProxy xs -> {|row} -> {|subrow}
56+
57+
instance nilRowSubset :: RowSubset row Nil () where subsetImpl _ _ = {}
58+
59+
instance consRowSubset
60+
::
61+
( IsSymbol sym
62+
, Cons sym a subrowWithoutSym subrowWithSym
63+
, Cons sym a srcWithoutSym src
64+
, Lacks sym subrowWithoutSym
65+
, RowSubset src rl subrowWithoutSym
66+
) => RowSubset src (Cons sym a rl) subrowWithSym where
67+
subsetImpl _ src = insert (SProxy :: SProxy sym) (get (SProxy :: SProxy sym) src) (subsetImpl (RLProxy :: RLProxy rl) src)
68+
69+
subsetRow
70+
:: rl subR src
71+
. ListToRow rl subR
72+
=> RowToList subR rl
73+
=> RowSubset src rl subR
74+
=> {|src}
75+
-> RProxy subR
76+
-> {|subR}
77+
subsetRow src _ = subsetImpl (RLProxy :: RLProxy rl) src
78+
79+
select
80+
:: m rec rl subR
81+
. Monad m
82+
=> RowSubset rec rl subR
83+
=> RowToList subR rl
84+
=> ListToRow rl subR
85+
=> RProxy subR
86+
-> Query m {|rec} {|subR}
87+
select proxy = (map (flip subsetRow proxy)) <$> ask
88+
89+
rename
90+
:: m inter input output sym sym' a
91+
. Monad m
92+
=> IsSymbol sym
93+
=> IsSymbol sym'
94+
=> Cons sym a inter input
95+
=> Lacks sym inter
96+
=> Cons sym' a inter output
97+
=> Lacks sym' inter
98+
=> SProxy sym
99+
-> SProxy sym'
100+
-> Query m {|input} {|output}
101+
rename proxy proxy' = (map (R.rename proxy proxy')) <$> ask
102+
103+
mutate
104+
:: m input output sym a
105+
. Monad m
106+
=> IsSymbol sym
107+
=> Lacks sym input
108+
=> Cons sym a input output
109+
=> SProxy sym
110+
-> ({|input} -> a)
111+
-> Query m {|input} {|output}
112+
mutate proxy f = (map (\r -> R.insert proxy (f r) r)) <$> ask
113+
114+
transmute
115+
:: m input sym a out
116+
. Monad m
117+
=> IsSymbol sym
118+
=> Lacks sym ()
119+
=> Cons sym a () out
120+
=> SProxy sym
121+
-> ({|input} -> a)
122+
-> Query m {|input} {|out}
123+
transmute proxy f = (map \r -> R.insert proxy (f r) {}) <$> ask
124+
125+
sort :: a. Ord a => List a -> List a
126+
sort xs = maybe mempty (\{ head, tail } -> (sort $ L.filter (_ <= head) tail) <> (head : (sort $ L.filter (_ > head) tail))) $ uncons xs

src/Main.purs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Main where
2+
3+
import Prelude
4+
import Effect (Effect)
5+
import Effect.Console (log)
6+
7+
main :: Effect Unit
8+
main = do
9+
log "Hello sailor!"

test/Main.purs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Test.Main where
2+
3+
import Prelude
4+
import Effect (Effect)
5+
import Effect.Console (log)
6+
7+
main :: Effect Unit
8+
main = do
9+
log "You should add some tests."

0 commit comments

Comments
 (0)