Created
September 11, 2017 17:03
-
-
Save kcsongor/9e0ae45c0d41e1c8aa4005742ab12182 to your computer and use it in GitHub Desktop.
RowToList with type families
This file contains hidden or 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
{-# LANGUAGE AllowAmbiguousTypes #-} | |
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE DeriveGeneric #-} | |
{-# LANGUAGE ExplicitForAll #-} | |
{-# LANGUAGE FlexibleContexts #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE PolyKinds #-} | |
{-# LANGUAGE TypeFamilies #-} | |
{-# LANGUAGE TypeOperators #-} | |
{-# LANGUAGE UndecidableInstances #-} | |
module RowToList where | |
import GHC.Generics | |
import Data.Kind (Type) | |
import GHC.TypeLits (Symbol) | |
import Data.Proxy (Proxy(..)) | |
-------------------------------------------------------------------------------- | |
-- * RowToList for Generics | |
type family GRowToList (rep :: Type -> Type) :: [(Symbol, Type)] where | |
GRowToList (l :*: r) | |
= GRowToList l ++ GRowToList r | |
GRowToList (S1 ('MetaSel ('Just name) _ _ _) (Rec0 a)) | |
= '[ '(name, a)] | |
GRowToList (M1 _ m a) | |
= GRowToList a | |
GRowToList U1 = '[] | |
-------------------------------------------------------------------------------- | |
-- * Utilities | |
type family (a :: [k]) ++ (b :: [k]) :: [k] where | |
'[] ++ bs = bs | |
(a ': as) ++ bs = a ': (as ++ bs) | |
-------------------------------------------------------------------------------- | |
-- * RowToList for records (becomes just a type synyonym) | |
type RowToList (record :: Type) = GRowToList (Rep record) | |
-------------------------------------------------------------------------------- | |
-- An example | |
data Tom = Tom | |
deriving Generic | |
data MyRecord = MyRecord | |
{ apple :: Int | |
, banana :: String | |
, orange :: Int | |
} deriving Generic | |
test :: forall record. Proxy (RowToList record) | |
test = Proxy | |
-- >>> :t test @MyRecord | |
-- test @MyRecord | |
-- :: Proxy '['("apple", Int), '("banana", [Char]), '("orange", Int)] | |
-- | |
-- >>> :t test @Tom | |
-- test @Tom :: Proxy '[] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment