vinyl 0.6.0 → 0.7.0
raw patch · 4 files changed
+167/−19 lines, 4 files
Files
- CHANGELOG.md +4/−0
- Data/Vinyl/CoRec.hs +4/−18
- Data/Vinyl/Curry.hs +157/−0
- vinyl.cabal +2/−1
CHANGELOG.md view
@@ -1,3 +1,7 @@+# 0.7.0+- Simplified `match`+- Added `Data.Vinyl.Curry`+ # 0.6.0 Added a `CoRec` (co-record) type constructed in the same style as the existing `Rec` type for records. A `CoRec` is an open sum type: a value of `CoRec [a,b,c]` is either an `a`, a `b`, *or* a `c`. In contrast a `Rec [a,b,c]` includes an `a`, a `b`, *and*, a `c`.
Data/Vinyl/CoRec.hs view
@@ -156,9 +156,8 @@ asA :: (t ∈ ts, RecApplicative ts) => proxy t -> CoRec Identity ts -> Maybe t asA p c@(CoRec _) = rget p $ coRecToRec' c --- | Pattern match on a CoRec by specifying handlers for each case. If the--- CoRec is non-empty this function is total. Note that the order of the--- Handlers has to match the type level list (t:ts).+-- | Pattern match on a CoRec by specifying handlers for each case. Note that+-- the order of the Handlers has to match the type level list (t:ts). -- -- >>> :{ -- let testCoRec = Col (Identity False) :: CoRec Identity [Int, String, Bool] in@@ -169,21 +168,8 @@ -- :& RNil -- :} -- "my Bool is not: True thus it is False"-match :: RecApplicative (t ': ts)- => CoRec Identity (t ': ts) -> Handlers (t ': ts) b -> b-match c hs = fromJust $ match' c hs- -- Since we require 'ts' both for the Handlers and the CoRec, Handlers- -- effectively defines a total function. Hence, we can safely use fromJust---- | Pattern match on a CoRec by specifying handlers for each case. The only case--- in which this can produce a Nothing is if the list ts is empty.-match' :: RecApplicative ts => CoRec Identity ts -> Handlers ts b -> Maybe b-match' c hs = match'' hs $ coRecToRec' c- where- match'' :: Handlers ts b -> Rec Maybe ts -> Maybe b- match'' RNil RNil = Nothing- match'' (H f :& _) (Just x :& _) = Just $ f x- match'' (H _ :& fs) (Nothing :& c') = match'' fs c'+match :: CoRec Identity ts -> Handlers ts b -> b+match (CoRec (Identity t)) hs = case rget Proxy hs of H f -> f t -- | Helper for handling a variant of a 'CoRec': either the function -- is applied to the variant or the type of the 'CoRec' is refined to
+ Data/Vinyl/Curry.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++{-|++Provides combinators for currying and uncurrying functions over arbitrary vinyl+records.++-}+module Data.Vinyl.Curry where++import Data.Vinyl+import Data.Vinyl.Functor++-- * Currying++class RecordCurry ts where+ {-|+ N-ary version of 'curry' over functorial records.++ Example specialized signatures:++ @+ rcurry :: (Rec Maybe '[Int, Double] -> Bool) -> Maybe Int -> Maybe Double -> Bool+ rcurry :: (Rec (Either Int) '[Double, String, ()] -> Int) -> Either Int Double -> Either Int String -> Either Int () -> Int+ rcurry :: (Rec f '[] -> Bool) -> Bool+ @++ -}+ rcurry :: (Rec f ts -> a) -> CurriedF f ts a++ {-|+ N-ary version of 'curry' over pure records.++ Example specialized signatures:++ @+ rcurry' :: (Rec Identity '[Int, Double] -> Bool) -> Int -> Double -> Bool+ rcurry' :: (Rec Identity '[Double, String, ()] -> Int) -> Double -> String -> () -> Int+ rcurry' :: (Rec Identity '[] -> Bool) -> Bool+ @++ -}+ rcurry' :: (Rec Identity ts -> a) -> Curried ts a+++instance RecordCurry '[] where+ rcurry f = f RNil+ {-# INLINABLE rcurry #-}+ rcurry' f = f RNil+ {-# INLINABLE rcurry' #-}++instance RecordCurry ts => RecordCurry (t ': ts) where+ rcurry f x = rcurry (\xs -> f (x :& xs))+ {-# INLINABLE rcurry #-}+ rcurry' f x = rcurry' (\xs -> f (Identity x :& xs))+ {-# INLINABLE rcurry' #-}++-- * Uncurrying++{-|+N-ary version of 'uncurry' over functorial records.++Example specialized signatures:++@+runcurry :: (Maybe Int -> Maybe Double -> String) -> Rec Maybe '[Int, Double] -> String+runcurry :: (IO FilePath -> String) -> Rec IO '[FilePath] -> String+runcurry :: Int -> Rec f '[] -> Int+@+-}+runcurry :: CurriedF f ts a -> Rec f ts -> a+runcurry x RNil = x+runcurry f (x :& xs) = runcurry (f x) xs+{-# INLINABLE runcurry #-}+++{-|+N-ary version of 'uncurry' over pure records.++Example specialized signatures:++@+runcurry' :: (Int -> Double -> String) -> Rec Identity '[Int, Double] -> String+runcurry' :: Int -> Rec Identity '[] -> Int+@++Example usage:++@+f :: Rec Identity '[Bool, Int, Double] -> Either Int Double+f = runcurry' $ \b x y -> if b then Left x else Right y+@+-}+runcurry' :: Curried ts a -> Rec Identity ts -> a+runcurry' x RNil = x+runcurry' f (Identity x :& xs) = runcurry' (f x) xs+{-# INLINABLE runcurry' #-}++-- * Applicative Combinators++{-|+Lift an N-ary function to work over a record of 'Applicative' computations.++>>> runcurryA' (+) (Just 2 :& Just 3 :& RNil)+Just 5++>>> runcurryA' (+) (Nothing :& Just 3 :& RNil)+Nothing+-}+runcurryA' :: (Applicative f) => Curried ts a -> Rec f ts -> f a+runcurryA' f = fmap (runcurry' f) . rtraverse (fmap Identity)+{-# INLINE runcurryA' #-}++{-|+Lift an N-ary function over types in @g@ to work over a record of 'Compose'd+'Applicative' computations. A more general version of 'runcurryA''.++Example specialized signatures:++@+runcurryA :: (g x -> g y -> a) -> Rec (Compose Maybe g) '[x, y] -> Maybe a+@+-}+runcurryA :: (Applicative f) => CurriedF g ts a -> Rec (Compose f g) ts -> f a+runcurryA f = fmap (runcurry f) . rtraverse getCompose+{-# INLINE runcurryA #-}++-- * Curried Function Types++{-|+For the list of types @ts@, @'Curried' ts a@ is a curried function type from+arguments of types in @ts@ to a result of type @a@.++>>> :kind! Curried '[Int, Bool, String] Int+Curried '[Int, Bool, String] Int :: *+= Int -> Bool -> [Char] -> Int+-}+type family Curried ts a where+ Curried '[] a = a+ Curried (t ': ts) a = t -> Curried ts a+++{-|+For the type-level list @ts@, @'CurriedF' f ts a@ is a curried function type+from arguments of type @f t@ for @t@ in @ts@, to a result of type @a@.++>>> :kind! CurriedF Maybe '[Int, Bool, String] Int+CurriedF Maybe '[Int, Bool, String] Int :: *+= Maybe Int -> Maybe Bool -> Maybe [Char] -> Int+-}+type family CurriedF (f :: u -> *) (ts :: [u]) a where+ CurriedF f '[] a = a+ CurriedF f (t ': ts) a = f t -> CurriedF f ts a
vinyl.cabal view
@@ -1,5 +1,5 @@ name: vinyl-version: 0.6.0+version: 0.7.0 synopsis: Extensible Records -- description: license: MIT@@ -25,6 +25,7 @@ , Data.Vinyl.Class.Method , Data.Vinyl.Core , Data.Vinyl.CoRec+ , Data.Vinyl.Curry , Data.Vinyl.Lens , Data.Vinyl.Derived , Data.Vinyl.TypeLevel