Skip to content

Instantly share code, notes, and snippets.

@7h3kk1d
Created July 17, 2024 19:02
Show Gist options
  • Save 7h3kk1d/bcc9566b48db82868300621e3eec818e to your computer and use it in GitHub Desktop.
Save 7h3kk1d/bcc9566b48db82868300621e3eec818e to your computer and use it in GitHub Desktop.
Basic lambda implementation of a table/dataframe
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