{-# language OverloadedStrings #-}
{-# language FlexibleInstances #-}
{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable, GeneralizedNewtypeDeriving #-}
{-# language ConstraintKinds #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}
-- {-# OPTIONS_HADDOCK show-extensions #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Core.Data.Frame
-- Description :  A sparse dataframe
-- Copyright   :  (c) Marco Zocca (2018-2019)
-- License     :  BSD-style
-- Maintainer  :  ocramz fripost org
-- Stability   :  experimental
-- Portability :  GHC
--
-- A general-purpose, row-oriented data frame.
--
-- As it is common in the sciences, the dataframe should be taken to contain
-- experimental datapoints as its rows, each being defined by a number of /features/.
--
-----------------------------------------------------------------------------
module Core.Data.Frame (
  -- * Frame
  Frame,
  -- ** Construction
  fromNEList, fromList,
  -- ** Access
  head, take, drop, zipWith, numRows, 
  -- ** Filtering 
  filter, 
  -- **
  groupWith, 
  -- ** Scans (row-wise cumulative operations)
  scanl, scanr,

  -- -- * Row
  -- Row,
  -- -- ** Construction
  -- fromKVs,
  -- -- *** (unsafe)
  -- mkRow, 
  -- -- ** Update
  -- insert, insertRowFun, insertRowFunM, 
  -- -- ** Access
  -- toList, keys, elems,
  -- -- ** Lookup
  -- HMR.lookup, lookupThrowM, lookupDefault, (!:), elemSatisfies, 
  -- -- ** Set operations
  -- union, unionWith,
  -- -- ** Traversals
  -- traverseWithKey,
  -- -- * One-Hot
  -- OneHot, 
  -- -- * Key constraint
  -- HMR.Key
  -- ** Vector-related
  toVector, fromVector,
  -- *** Sorting
  ) where

import qualified Control.Monad as CM (filterM)
import Data.Maybe (fromMaybe)
import qualified Data.Vector as V
import qualified Data.List.NonEmpty as NE

import Prelude hiding (filter, zipWith, lookup, foldl, foldr, scanl, scanr, head, take, drop)

-- $setup
-- >>> import qualified Heidi.Data.Row.HashMap as HMR
-- >>> let row0 = HMR.fromList [(0, 'a'), (3, 'b')] :: HMR.Row Int Char
-- >>> let row1 = HMR.fromList [(0, 'x'), (1, 'b'), (666, 'z')] :: HMR.Row Int Char
-- >>> let book1 = HMR.fromList [("item", "book"), ("id.0", "129"), ("qty", "1")]
-- >>> let book2 = HMR.fromList [("item", "book"), ("id.0", "129"), ("qty", "5")]
-- >>> let ball = HMR.fromList [("item", "ball"), ("id.0", "234"), ("qty", "1")]
-- >>> let bike = HMR.fromList [("item", "bike"), ("id.0", "410"), ("qty", "1")]
-- >>> let t0 = fromList [ book1, ball, bike, book2 ] :: Frame (HMR.Row String String)
-- >>> let r1 = HMR.fromList [("id.1", "129"), ("price", "100")]
-- >>> let r2 = HMR.fromList [("id.1", "234"), ("price", "50")]
-- >>> let r3 = HMR.fromList [("id.1", "3"), ("price", "150")]
-- >>> let r4 = HMR.fromList [("id.1", "99"), ("price", "30")]
-- >>> let t1 = fromList [ r1, r2, r3, r4 ] :: Frame (HMR.Row String String)



-- [NOTE : table Alternative instance] 
-- 
-- https://github.com/Gabriel439/Haskell-Bears-Library/blob/master/src/Bears.hs
--
-- 'Table' has Applicative and Alternative instances
-- -- *  for Alternative, we need the possibility of an empty table (to implement `empty`). Currently this is impossible due to the 'NonEmpty' list implementation.

-- [NOTE : column universe and table pretty printing]
--
-- Currently this 'Table' implementation doesn't know anything of its row type, including the type of its keys and values.
-- To pretty-print our tables, we'd like instead to know the "universe of columns", i.e. all possible columns used in every row (or at least in the first N rows)


-- | A 'Frame' is a non-empty list of rows.
newtype Frame row = Frame {
    -- nFrameRows :: Maybe Int  -- ^ Nothing means unknown
    Frame row -> NonEmpty row
tableRows :: NE.NonEmpty row } deriving (Int -> Frame row -> ShowS
[Frame row] -> ShowS
Frame row -> String
(Int -> Frame row -> ShowS)
-> (Frame row -> String)
-> ([Frame row] -> ShowS)
-> Show (Frame row)
forall row. Show row => Int -> Frame row -> ShowS
forall row. Show row => [Frame row] -> ShowS
forall row. Show row => Frame row -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Frame row] -> ShowS
$cshowList :: forall row. Show row => [Frame row] -> ShowS
show :: Frame row -> String
$cshow :: forall row. Show row => Frame row -> String
showsPrec :: Int -> Frame row -> ShowS
$cshowsPrec :: forall row. Show row => Int -> Frame row -> ShowS
Show, a -> Frame b -> Frame a
(a -> b) -> Frame a -> Frame b
(forall a b. (a -> b) -> Frame a -> Frame b)
-> (forall a b. a -> Frame b -> Frame a) -> Functor Frame
forall a b. a -> Frame b -> Frame a
forall a b. (a -> b) -> Frame a -> Frame b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Frame b -> Frame a
$c<$ :: forall a b. a -> Frame b -> Frame a
fmap :: (a -> b) -> Frame a -> Frame b
$cfmap :: forall a b. (a -> b) -> Frame a -> Frame b
Functor, a -> Frame a -> Bool
Frame m -> m
Frame a -> [a]
Frame a -> Bool
Frame a -> Int
Frame a -> a
Frame a -> a
Frame a -> a
Frame a -> a
(a -> m) -> Frame a -> m
(a -> m) -> Frame a -> m
(a -> b -> b) -> b -> Frame a -> b
(a -> b -> b) -> b -> Frame a -> b
(b -> a -> b) -> b -> Frame a -> b
(b -> a -> b) -> b -> Frame a -> b
(a -> a -> a) -> Frame a -> a
(a -> a -> a) -> Frame a -> a
(forall m. Monoid m => Frame m -> m)
-> (forall m a. Monoid m => (a -> m) -> Frame a -> m)
-> (forall m a. Monoid m => (a -> m) -> Frame a -> m)
-> (forall a b. (a -> b -> b) -> b -> Frame a -> b)
-> (forall a b. (a -> b -> b) -> b -> Frame a -> b)
-> (forall b a. (b -> a -> b) -> b -> Frame a -> b)
-> (forall b a. (b -> a -> b) -> b -> Frame a -> b)
-> (forall a. (a -> a -> a) -> Frame a -> a)
-> (forall a. (a -> a -> a) -> Frame a -> a)
-> (forall a. Frame a -> [a])
-> (forall a. Frame a -> Bool)
-> (forall a. Frame a -> Int)
-> (forall a. Eq a => a -> Frame a -> Bool)
-> (forall a. Ord a => Frame a -> a)
-> (forall a. Ord a => Frame a -> a)
-> (forall a. Num a => Frame a -> a)
-> (forall a. Num a => Frame a -> a)
-> Foldable Frame
forall a. Eq a => a -> Frame a -> Bool
forall a. Num a => Frame a -> a
forall a. Ord a => Frame a -> a
forall m. Monoid m => Frame m -> m
forall a. Frame a -> Bool
forall a. Frame a -> Int
forall a. Frame a -> [a]
forall a. (a -> a -> a) -> Frame a -> a
forall m a. Monoid m => (a -> m) -> Frame a -> m
forall b a. (b -> a -> b) -> b -> Frame a -> b
forall a b. (a -> b -> b) -> b -> Frame a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
product :: Frame a -> a
$cproduct :: forall a. Num a => Frame a -> a
sum :: Frame a -> a
$csum :: forall a. Num a => Frame a -> a
minimum :: Frame a -> a
$cminimum :: forall a. Ord a => Frame a -> a
maximum :: Frame a -> a
$cmaximum :: forall a. Ord a => Frame a -> a
elem :: a -> Frame a -> Bool
$celem :: forall a. Eq a => a -> Frame a -> Bool
length :: Frame a -> Int
$clength :: forall a. Frame a -> Int
null :: Frame a -> Bool
$cnull :: forall a. Frame a -> Bool
toList :: Frame a -> [a]
$ctoList :: forall a. Frame a -> [a]
foldl1 :: (a -> a -> a) -> Frame a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> Frame a -> a
foldr1 :: (a -> a -> a) -> Frame a -> a
$cfoldr1 :: forall a. (a -> a -> a) -> Frame a -> a
foldl' :: (b -> a -> b) -> b -> Frame a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> Frame a -> b
foldl :: (b -> a -> b) -> b -> Frame a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> Frame a -> b
foldr' :: (a -> b -> b) -> b -> Frame a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> Frame a -> b
foldr :: (a -> b -> b) -> b -> Frame a -> b
$cfoldr :: forall a b. (a -> b -> b) -> b -> Frame a -> b
foldMap' :: (a -> m) -> Frame a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> Frame a -> m
foldMap :: (a -> m) -> Frame a -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> Frame a -> m
fold :: Frame m -> m
$cfold :: forall m. Monoid m => Frame m -> m
Foldable, Functor Frame
Foldable Frame
Functor Frame
-> Foldable Frame
-> (forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> Frame a -> f (Frame b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    Frame (f a) -> f (Frame a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> Frame a -> m (Frame b))
-> (forall (m :: * -> *) a. Monad m => Frame (m a) -> m (Frame a))
-> Traversable Frame
(a -> f b) -> Frame a -> f (Frame b)
forall (t :: * -> *).
Functor t
-> Foldable t
-> (forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a. Monad m => Frame (m a) -> m (Frame a)
forall (f :: * -> *) a. Applicative f => Frame (f a) -> f (Frame a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Frame a -> m (Frame b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Frame a -> f (Frame b)
sequence :: Frame (m a) -> m (Frame a)
$csequence :: forall (m :: * -> *) a. Monad m => Frame (m a) -> m (Frame a)
mapM :: (a -> m b) -> Frame a -> m (Frame b)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Frame a -> m (Frame b)
sequenceA :: Frame (f a) -> f (Frame a)
$csequenceA :: forall (f :: * -> *) a. Applicative f => Frame (f a) -> f (Frame a)
traverse :: (a -> f b) -> Frame a -> f (Frame b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Frame a -> f (Frame b)
$cp2Traversable :: Foldable Frame
$cp1Traversable :: Functor Frame
Traversable, b -> Frame row -> Frame row
NonEmpty (Frame row) -> Frame row
Frame row -> Frame row -> Frame row
(Frame row -> Frame row -> Frame row)
-> (NonEmpty (Frame row) -> Frame row)
-> (forall b. Integral b => b -> Frame row -> Frame row)
-> Semigroup (Frame row)
forall b. Integral b => b -> Frame row -> Frame row
forall row. NonEmpty (Frame row) -> Frame row
forall row. Frame row -> Frame row -> Frame row
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall row b. Integral b => b -> Frame row -> Frame row
stimes :: b -> Frame row -> Frame row
$cstimes :: forall row b. Integral b => b -> Frame row -> Frame row
sconcat :: NonEmpty (Frame row) -> Frame row
$csconcat :: forall row. NonEmpty (Frame row) -> Frame row
<> :: Frame row -> Frame row -> Frame row
$c<> :: forall row. Frame row -> Frame row -> Frame row
Semigroup)

-- | Take the first row of a 'Frame'
--
-- >>> head (fromList [row0, row1]) == row0
-- True
head :: Frame row -> row
head :: Frame row -> row
head = NonEmpty row -> row
forall a. NonEmpty a -> a
NE.head (NonEmpty row -> row)
-> (Frame row -> NonEmpty row) -> Frame row -> row
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frame row -> NonEmpty row
forall row. Frame row -> NonEmpty row
tableRows

-- | Take the first @n@ rows of a Frame
take :: Int -> Frame r -> [r]
take :: Int -> Frame r -> [r]
take Int
n = Int -> NonEmpty r -> [r]
forall a. Int -> NonEmpty a -> [a]
NE.take Int
n (NonEmpty r -> [r]) -> (Frame r -> NonEmpty r) -> Frame r -> [r]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frame r -> NonEmpty r
forall row. Frame row -> NonEmpty row
tableRows

-- | Drop the first @n@ rows of a Frame
drop :: Int -> Frame r -> [r]
drop :: Int -> Frame r -> [r]
drop Int
n = Int -> NonEmpty r -> [r]
forall a. Int -> NonEmpty a -> [a]
NE.drop Int
n (NonEmpty r -> [r]) -> (Frame r -> NonEmpty r) -> Frame r -> [r]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frame r -> NonEmpty r
forall row. Frame row -> NonEmpty row
tableRows

-- | Construct a table given a non-empty list of rows
--
-- >>> (head <$> fromNEList [row0, row1]) == Just row0
-- True
-- >>> fromNEList []
-- Nothing
fromNEList :: [row] -> Maybe (Frame row)
fromNEList :: [row] -> Maybe (Frame row)
fromNEList [row]
l = NonEmpty row -> Frame row
forall row. NonEmpty row -> Frame row
Frame (NonEmpty row -> Frame row)
-> Maybe (NonEmpty row) -> Maybe (Frame row)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [row] -> Maybe (NonEmpty row)
forall a. [a] -> Maybe (NonEmpty a)
NE.nonEmpty [row]
l

-- | Construct a table given a list of rows. Crashes if the input list is empty
fromList :: [row] -> Frame row
fromList :: [row] -> Frame row
fromList = NonEmpty row -> Frame row
forall row. NonEmpty row -> Frame row
Frame (NonEmpty row -> Frame row)
-> ([row] -> NonEmpty row) -> [row] -> Frame row
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [row] -> NonEmpty row
forall a. [a] -> NonEmpty a
NE.fromList

toList :: Frame a -> [a]
toList :: Frame a -> [a]
toList = NonEmpty a -> [a]
forall a. NonEmpty a -> [a]
NE.toList (NonEmpty a -> [a]) -> (Frame a -> NonEmpty a) -> Frame a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frame a -> NonEmpty a
forall row. Frame row -> NonEmpty row
tableRows

-- | Zip two frames with a row combining function
zipWith :: (a -> b -> row)
        -> Frame a -> Frame b -> Frame row
zipWith :: (a -> b -> row) -> Frame a -> Frame b -> Frame row
zipWith a -> b -> row
f Frame a
tt1 Frame b
tt2 = NonEmpty row -> Frame row
forall row. NonEmpty row -> Frame row
Frame (NonEmpty row -> Frame row) -> NonEmpty row -> Frame row
forall a b. (a -> b) -> a -> b
$ (a -> b -> row) -> NonEmpty a -> NonEmpty b -> NonEmpty row
forall a b c.
(a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c
NE.zipWith a -> b -> row
f (Frame a -> NonEmpty a
forall row. Frame row -> NonEmpty row
tableRows Frame a
tt1) (Frame b -> NonEmpty b
forall row. Frame row -> NonEmpty row
tableRows Frame b
tt2)



-- | Filters a 'Frame' according to a predicate. Returns Nothing only if the resulting table is empty (i.e. if no rows satisfy the predicate).
--
filter :: (row -> Bool) -> Frame row -> Maybe (Frame row)
filter :: (row -> Bool) -> Frame row -> Maybe (Frame row)
filter row -> Bool
ff = [row] -> Maybe (Frame row)
forall row. [row] -> Maybe (Frame row)
fromNEList ([row] -> Maybe (Frame row))
-> (Frame row -> [row]) -> Frame row -> Maybe (Frame row)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (row -> Bool) -> NonEmpty row -> [row]
forall a. (a -> Bool) -> NonEmpty a -> [a]
NE.filter row -> Bool
ff (NonEmpty row -> [row])
-> (Frame row -> NonEmpty row) -> Frame row -> [row]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frame row -> NonEmpty row
forall row. Frame row -> NonEmpty row
tableRows

-- | This generalizes the list-based 'filter' function.
filterA :: Applicative f =>
           (row -> f Bool) -> Frame row -> f (Maybe (Frame row))
filterA :: (row -> f Bool) -> Frame row -> f (Maybe (Frame row))
filterA row -> f Bool
fm Frame row
t = [row] -> Maybe (Frame row)
forall row. [row] -> Maybe (Frame row)
fromNEList ([row] -> Maybe (Frame row)) -> f [row] -> f (Maybe (Frame row))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (row -> f Bool) -> [row] -> f [row]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
CM.filterM row -> f Bool
fm (Frame row -> [row]
forall a. Frame a -> [a]
toList Frame row
t)



-- filterInt2 k1 k2 =
--   filterDecode ((>=) <$> HMR.scientific k1 <*> HMR.scientific k2)



-- | Left-associative scan
scanl :: (b -> a -> b) -> b -> Frame a -> Frame b
scanl :: (b -> a -> b) -> b -> Frame a -> Frame b
scanl b -> a -> b
f b
z Frame a
tt = NonEmpty b -> Frame b
forall row. NonEmpty row -> Frame row
Frame (NonEmpty b -> Frame b) -> NonEmpty b -> Frame b
forall a b. (a -> b) -> a -> b
$ (b -> a -> b) -> b -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) b a.
Foldable f =>
(b -> a -> b) -> b -> f a -> NonEmpty b
NE.scanl b -> a -> b
f b
z (Frame a -> NonEmpty a
forall row. Frame row -> NonEmpty row
tableRows Frame a
tt)

-- | Right-associative scan
scanr :: (a -> b -> b) -> b -> Frame a -> Frame b
scanr :: (a -> b -> b) -> b -> Frame a -> Frame b
scanr a -> b -> b
f b
z Frame a
tt = NonEmpty b -> Frame b
forall row. NonEmpty row -> Frame row
Frame (NonEmpty b -> Frame b) -> NonEmpty b -> Frame b
forall a b. (a -> b) -> a -> b
$ (a -> b -> b) -> b -> NonEmpty a -> NonEmpty b
forall (f :: * -> *) a b.
Foldable f =>
(a -> b -> b) -> b -> f a -> NonEmpty b
NE.scanr a -> b -> b
f b
z (Frame a -> NonEmpty a
forall row. Frame row -> NonEmpty row
tableRows Frame a
tt)

-- | 'groupWith' takes row comparison function and a list and returns a list of lists such that the concatenation of the result is equal to the argument. Moreover, each sublist in the result contains only elements that satisfy the comparison. 
groupWith :: (row -> row -> Bool) -> Frame row -> [Frame row]
groupWith :: (row -> row -> Bool) -> Frame row -> [Frame row]
groupWith row -> row -> Bool
f Frame row
t = NonEmpty row -> Frame row
forall row. NonEmpty row -> Frame row
Frame (NonEmpty row -> Frame row) -> [NonEmpty row] -> [Frame row]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (row -> row -> Bool) -> NonEmpty row -> [NonEmpty row]
forall (f :: * -> *) a.
Foldable f =>
(a -> a -> Bool) -> f a -> [NonEmpty a]
NE.groupBy row -> row -> Bool
f (Frame row -> NonEmpty row
forall row. Frame row -> NonEmpty row
tableRows Frame row
t)

-- | 'groupWithM' uses a comparison function that Maybe returns a Bool. This is useful when used in conjuction with lookup-based logic.
groupWithM :: (row -> row -> Maybe Bool) -> Frame row -> [Frame row]
groupWithM :: (row -> row -> Maybe Bool) -> Frame row -> [Frame row]
groupWithM row -> row -> Maybe Bool
fm = (row -> row -> Bool) -> Frame row -> [Frame row]
forall row. (row -> row -> Bool) -> Frame row -> [Frame row]
groupWith row -> row -> Bool
f' where
  f' :: row -> row -> Bool
f' row
r1 row
r2 = Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
False (row -> row -> Maybe Bool
fm row
r1 row
r2)

-- | /O(n)/ Count the number of rows in the table
--
-- >>> numRows t0
-- 4
numRows :: Frame row -> Int 
numRows :: Frame row -> Int
numRows = Frame row -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length



-- | Produce a 'Vector' of rows
toVector :: Frame row -> V.Vector row
toVector :: Frame row -> Vector row
toVector = [row] -> Vector row
forall a. [a] -> Vector a
V.fromList ([row] -> Vector row)
-> (Frame row -> [row]) -> Frame row -> Vector row
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty row -> [row]
forall a. NonEmpty a -> [a]
NE.toList (NonEmpty row -> [row])
-> (Frame row -> NonEmpty row) -> Frame row -> [row]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Frame row -> NonEmpty row
forall row. Frame row -> NonEmpty row
tableRows

-- | Produce a Frame from a 'Vector' of rows
fromVector :: V.Vector row -> Maybe (Frame row)
fromVector :: Vector row -> Maybe (Frame row)
fromVector = [row] -> Maybe (Frame row)
forall row. [row] -> Maybe (Frame row)
fromNEList ([row] -> Maybe (Frame row))
-> (Vector row -> [row]) -> Vector row -> Maybe (Frame row)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector row -> [row]
forall a. Vector a -> [a]
V.toList