Created
July 17, 2024 19:02
-
-
Save 7h3kk1d/bcc9566b48db82868300621e3eec818e to your computer and use it in GitHub Desktop.
Basic lambda implementation of a table/dataframe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.jnape.palatable.lambda; | |
import com.jnape.palatable.lambda.adt.hlist.HList; | |
import com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith; | |
import com.jnape.palatable.lambda.monoid.builtin.Join; | |
import java.util.List; | |
import static com.jnape.palatable.lambda.adt.hlist.HList.nil; | |
import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; | |
import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; | |
import static java.util.Arrays.asList; | |
// Column-oriented dataframe. Does not currently have any sort of human-readable column headers or lenses to retrieve them. | |
public sealed interface Table<RowType extends HList> permits Table.NilTable, Table.ConsTable { | |
record NilTable() implements Table<HList.HNil> { | |
@Override | |
public Iterable<HList.HNil> rows() { | |
return repeat(nil()); // TODO: Rows without columns? TODO: Make this empty and add a singleton column | |
} | |
@Override | |
public String toString() { | |
return "||"; | |
} | |
} | |
record ConsTable<HeadColumn, TailRow extends HList, TailTable extends Table<TailRow>>( | |
List<HeadColumn> headColumn, TailTable tailColumns) implements Table<HList.HCons<HeadColumn, TailRow>> { | |
@Override | |
public Iterable<HList.HCons<HeadColumn, TailRow>> rows() { | |
return ZipWith.zipWith(HList.HCons::cons, headColumn, this.tailColumns.rows()); | |
} | |
@Override | |
public String toString() { | |
return Join.join() | |
.reduceLeft(map(headColumnTailRowHCons -> pipeDelimited(headColumnTailRowHCons, 5) + "\n", rows())); | |
} | |
} | |
Iterable<RowType> rows(); | |
static NilTable emptyTable() { | |
return new NilTable(); | |
} | |
default <T> ConsTable<T, RowType, Table<RowType>> prependColumn(List<T> column) { | |
return new ConsTable<>(column, this); | |
} | |
@SuppressWarnings("unchecked") | |
static <HC, TR extends HList, HLHC extends HList.HCons<HC, TR>, TT extends Table<TR>> ConsTable<HC, TR, TT> reify(Table<HLHC> rest) { | |
return (ConsTable<HC, TR, TT>) rest; // This is a safe cast. I need a way to prove that though. | |
} | |
// TODO Convert HList to used sealed interface for pattern matching and make recursive | |
private static String pipeDelimited(HList headColumnTailRowHCons, int padding) { | |
StringBuilder body = new StringBuilder("|"); | |
HList next = headColumnTailRowHCons; | |
while (next != nil()) { | |
HList.HCons<?, ?> hCons = (HList.HCons<?, ?>) next; | |
body.append(String.format("%10s", hCons.head())); | |
next = hCons.tail(); | |
if (next != nil()) | |
body.append("|"); | |
} | |
String string = body.append("|").toString(); | |
return string; | |
} | |
static void main(String[] args) { | |
ConsTable<Boolean, HList.HCons<String, HList.HCons<Integer, HList.HNil>>, Table<HList.HCons<String, HList.HCons<Integer, HList.HNil>>>> table = emptyTable() | |
.prependColumn(asList(1, 2, 3, 4, 5)) | |
.prependColumn(asList("A", "B", "C", "D")) | |
.prependColumn(asList(true, false, true, false)); | |
/* | |
| true| A| 1| | |
| false| B| 2| | |
| true| C| 3| | |
| false| D| 4| | |
*/ | |
System.out.println(table); | |
/* | |
HList{ true :: A :: 1 } | |
HList{ false :: B :: 2 } | |
HList{ true :: C :: 3 } | |
HList{ false :: D :: 4 } | |
*/ | |
table.rows() | |
.forEach(System.out::println); | |
/* | |
A | |
B | |
C | |
D | |
*/ | |
reify(table.tailColumns()) | |
.headColumn() | |
.forEach(System.out::println); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment