Skip to content

Instantly share code, notes, and snippets.

@mchav
Created January 22, 2024 18:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mchav/e32ae3a8faa46d5a4bbcb8d709f76b13 to your computer and use it in GitHub Desktop.
Save mchav/e32ae3a8faa46d5a4bbcb8d709f76b13 to your computer and use it in GitHub Desktop.
DataFrames using GADTs and Dynamic Typing
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
module Main where
import Data.Map (Map)
import Data.Type.Equality
import Data.Typeable (Typeable)
import Type.Reflection
import qualified Data.Map as M
import Unsafe.Coerce
type C a = [a]
data Column where
MkColumn :: (Typeable a) => {c :: [a]} -> Column
data DataFrame = DataFrame {
columns :: Map String Column
}
getColumn :: (Typeable a) => DataFrame -> String -> [a]
getColumn d name = case (M.!) (columns d) name of
(MkColumn {c = column}) -> unsafeCoerce column :: [a]
apply :: forall b. (Typeable b) =>
DataFrame ->
String ->
(b -> b) ->
DataFrame
apply d columnName f =
DataFrame { columns = M.alter alteration columnName (columns d) }
where
alteration :: Maybe Column -> Maybe Column
alteration c' = case c' of
Nothing -> error $ "No such column: " ++ columnName
Just (MkColumn {c = column' :: [a]}) ->
let repb :: Type.Reflection.TypeRep b = Type.Reflection.typeRep @b
repa :: Type.Reflection.TypeRep a = Type.Reflection.typeRep @a
in case repa `testEquality` repb of
Nothing -> error "Wrong type"
Just Refl -> Just (MkColumn { c = map f column' })
main :: IO ()
main = do
let frame = DataFrame { columns = M.fromList [
("numbers", MkColumn { c = ([1..50] :: [Int])}),
("letters", MkColumn { c = ['a'..'z']})
]}
print $ (getColumn (apply frame "numbers" ((+2) :: Int -> Int) ) "numbers" :: [Int])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment