{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
module Data.Vinyl.Derived where
import Data.Proxy
import Data.Vinyl.ARec
import Data.Vinyl.Core
import Data.Vinyl.Functor
import Data.Vinyl.Lens
import Data.Vinyl.TypeLevel (Fst, Snd, RIndex)
import GHC.OverloadedLabels
import GHC.TypeLits
type a ::: b = '(a, b)
type FieldRec = Rec ElField
type AFieldRec ts = ARec ElField ts
type HList = Rec Identity
type LazyHList = Rec Thunk
getField :: ElField '(s,t) -> t
getField (Field x) = x
getLabel :: forall s t. ElField '(s,t) -> String
getLabel (Field _) = symbolVal (Proxy::Proxy s)
fieldMap :: (a -> b) -> ElField '(s,a) -> ElField '(s,b)
fieldMap f (Field x) = Field (f x)
{-# INLINE fieldMap #-}
rfield :: Functor f => (a -> f b) -> ElField '(s,a) -> f (ElField '(s,b))
rfield f (Field x) = fmap Field (f x)
{-# INLINE rfield #-}
infix 8 =:
(=:) :: KnownSymbol l => Label (l :: Symbol) -> (v :: *) -> ElField (l ::: v)
_ =: v = Field v
rgetf
:: forall l f v record us.
(HasField record l us us v v, RecElemFCtx record f)
=> Label l -> record f us -> f (l ::: v)
rgetf _ = rget @(l ::: v)
rvalf
:: (HasField record l us us v v, RecElemFCtx record ElField)
=> Label l -> record ElField us -> v
rvalf x = getField . rgetf x
rputf' :: forall l v v' record us us'.
(HasField record l us us' v v', KnownSymbol l, RecElemFCtx record ElField)
=> Label l -> v' -> record ElField us -> record ElField us'
rputf' _ = rput' @(l:::v) . (Field :: v' -> ElField '(l,v'))
rputf :: forall l v record us.
(HasField record l us us v v, KnownSymbol l, RecElemFCtx record ElField)
=> Label l -> v -> record ElField us -> record ElField us
rputf _ = rput @(l:::v) . Field
rlensfL' :: forall l v v' record g f us us'.
(Functor g, HasField record l us us' v v', RecElemFCtx record f)
=> Label l
-> (f (l ::: v) -> g (f (l ::: v')))
-> record f us
-> g (record f us')
rlensfL' _ f = rlens' @(l ::: v) f
rlensfL :: forall l v record g f us.
(Functor g, HasField record l us us v v, RecElemFCtx record f)
=> Label l
-> (f (l ::: v) -> g (f (l ::: v)))
-> record f us
-> g (record f us)
rlensfL _ f = rlens' @(l ::: v) f
rlensf' :: forall l v v' record g us us'.
(Functor g, HasField record l us us' v v', RecElemFCtx record ElField)
=> Label l -> (v -> g v') -> record ElField us -> g (record ElField us')
rlensf' _ f = rlens' @(l ::: v) (rfield f)
rlensf :: forall l v record g us.
(Functor g, HasField record l us us v v, RecElemFCtx record ElField)
=> Label l -> (v -> g v) -> record ElField us -> g (record ElField us)
rlensf _ f = rlens @(l ::: v) (rfield f)
(=:=) :: KnownSymbol s => Label (s :: Symbol) -> a -> FieldRec '[ '(s,a) ]
(=:=) _ x = Field x :& RNil
data SField (field :: k) = SField
instance Eq (SField a) where _ == _ = True
instance Ord (SField a) where compare _ _ = EQ
instance KnownSymbol s => Show (SField '(s,t)) where
show _ = "SField "++symbolVal (Proxy::Proxy s)
type family FieldType l fs where
FieldType l '[] = TypeError ('Text "Cannot find label "
':<>: 'ShowType l
':<>: 'Text " in fields")
FieldType l ((l ::: v) ': fs) = v
FieldType l ((l' ::: v') ': fs) = FieldType l fs
type HasField record l fs fs' v v' =
(RecElem record (l ::: v) (l ::: v') fs fs' (RIndex (l ::: v) fs), FieldType l fs ~ v, FieldType l fs' ~ v')
data Label (a :: Symbol) = Label
deriving (Eq, Show)
instance s ~ s' => IsLabel s (Label s') where
#if __GLASGOW_HASKELL__ < 802
fromLabel _ = Label
#else
fromLabel = Label
#endif
class (KnownSymbol (Fst a), a ~ '(Fst a, Snd a)) => KnownField a where
instance KnownSymbol l => KnownField (l ::: v) where
type AllFields fs = (RPureConstrained KnownField fs, RecApplicative fs, RApply fs)
rmapf :: AllFields fs
=> (forall a. KnownField a => f a -> g a)
-> Rec f fs -> Rec g fs
rmapf f = (rpureConstrained @KnownField (Lift f) <<*>>)
type family Unlabeled ts where
Unlabeled '[] = '[]
Unlabeled ('(s,x) ': xs) = x ': Unlabeled xs
class StripFieldNames ts where
stripNames :: Rec ElField ts -> Rec Identity (Unlabeled ts)
stripNames' :: Functor f => Rec (f :. ElField) ts -> Rec f (Unlabeled ts)
withNames :: Rec Identity (Unlabeled ts) -> Rec ElField ts
withNames' :: Functor f => Rec f (Unlabeled ts) -> Rec (f :. ElField) ts
instance StripFieldNames '[] where
stripNames RNil = RNil
stripNames' RNil = RNil
withNames RNil = RNil
withNames' RNil = RNil
instance (KnownSymbol s, StripFieldNames ts) => StripFieldNames ('(s,t) ': ts) where
stripNames (Field x :& xs) = pure x :& stripNames xs
stripNames' (Compose x :& xs) = fmap getField x :& stripNames' xs
withNames (Identity x :& xs) = Field x :& withNames xs
withNames' (x :& xs) = Compose (fmap Field x) :& withNames' xs
rpuref :: AllFields fs => (forall a. KnownField a => f a) -> Rec f fs
rpuref f = rpureConstrained @KnownField f
(<<$$>>)
:: AllFields fs
=> (forall a. KnownField a => f a -> g a) -> Rec f fs -> Rec g fs
(<<$$>>) = rmapf
rlabels :: AllFields fs => Rec (Const String) fs
rlabels = rpuref getLabel'
where getLabel' :: forall l v. KnownSymbol l
=> Const String (l ::: v)
getLabel' = Const (symbolVal (Proxy::Proxy l))