rust-dataframe / discussion

Use the issues for discussion
24 stars 1 forks source link

Const Generics #7

Open jesskfullwood opened 4 years ago

jesskfullwood commented 4 years ago

I'm still interested in the ideas behind this project. Had a play to see how const generics might make the API more expressive, and I think it has a lot of potential. The idea is that const-generics would allows you to insert and retrieve columns into the dataframe by name, and it would be a compile error to ask for a column that didn't exist. Take this toy code (using frunk which is great):

#![feature(const_generics)]

use frunk::hlist::{HList, HCons, HNil, Selector};

struct Column<T, const S: &'static str> {    // S is the 'name' of the column
    inner: Vec<T>
}

impl<T, const S: &'static str> Column<T, S> {
    fn new(inner: Vec<T>) -> Self {
        Self {
            inner
        }
    }
}

struct Frame<H: HList> {
    inner: H
}

impl Frame<HNil> {
    fn new() -> Self {
        Self {
            inner: HNil
        }
    }
}

impl<H: HList> Frame<H> {
    fn add<T, const S: &'static str>(self, col: Vec<T>) -> Frame<HCons<Column<T, S>, H>> {
        let column = Column::new(col);
        Frame {
            inner: HCons{
                head: column,
                tail: self.inner
            }
        }
    }

    pub fn get<T, Index, const S: &'static str>(&self) -> &Column<T, S>
    where
        H: Selector<Column<T, S>, Index>,
    {
        Selector::get(&self.inner)
    }
}

fn main() {
    let frame = Frame::new()
        .add::<u32, "col1">(vec![1,2,3])
        .add::<u32, "col2">(vec![1,2,3]);
    let col = frame.get::<_, _, "col1">();  // OK
    // let col = frame.get::<_, _, "missing">();  // compile error!
}

This is pretty neat! Problem: it crashes with an ICE at the moment. But it will work soon!

xcaptain commented 4 years ago

@jesskfullwood Great, I implemented get_column based on your work

pub fn get_column<Index, T>(&self) -> T
where Col: Sculptor<T, Index>
{
    let (target, _): (T, _) = self.inner_cols.clone().sculpt();
    target
}

using Sculptor go get the specific columns.

I also implemented a simple get_row

pub fn get_row<Index, T1: Copy, const S1: &'static str, T2: Copy, const S2: &'static str>(&self, idx: usize) -> (T1, T2)
where Col: Sculptor<HCons<Column<T1, S1>, HCons<Column<T2, S2>, HNil>>, Index>
{
    let (target, _): (HCons<Column<T1, S1>, HCons<Column<T2, S2>, HNil>>, _) = self.inner_cols.clone().sculpt();
    let list: (Column<T1, S1>, Column<T2, S2>) = target.into();
    (list.0.inner[idx], list.1.inner[idx])
}

This get_row works, but is not generic, do you have any idea on implement a better get_row?