Created
October 1, 2020 15:51
-
-
Save Lysxia/f50ba99cdca1faa55dd598e707c0b594 to your computer and use it in GitHub Desktop.
This file contains 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 DeriveAnyClass, DeriveGeneric, DataKinds, PolyKinds, GADTs, TypeOperators, RankNTypes, ScopedTypeVariables, TypeApplications #-} | |
import Generics.SOP | |
import qualified GHC.Generics as GHC (Generic) | |
import Data.Proxy | |
type Optic f s a = (a -> f a) -> (s -> f s) | |
type Trav s a = forall f. Applicative f => Optic f s a | |
newtype Trav_ s a = Trav_ (Trav s a) | |
mkTraversals :: forall a. Generic a => POP (Trav_ a) (Code a) | |
mkTraversals = mkTraversalsPOP (hpure Proxy) gtrav | |
-- Implementation | |
gtrav :: Generic a => Trav a (Rep a) | |
gtrav f = fmap to . f . from | |
mkTraversalsPOP :: forall s xss. POP Proxy xss -> Trav s (SOP I xss) -> POP (Trav_ s) xss | |
mkTraversalsPOP (POP xss) trav = POP (mkTraversalsNP2 xss trav') | |
where | |
trav' :: Trav s (NS (NP I) xss) | |
trav' f = trav (fmap SOP . f . unSOP) | |
mkTraversalsNP2 :: forall s xss. NP (NP Proxy) xss -> Trav s (NS (NP I) xss) -> NP (NP (Trav_ s)) xss | |
mkTraversalsNP2 Nil _ = Nil | |
mkTraversalsNP2 ((xs :: NP Proxy xs) :* (xss :: NP (NP Proxy) xss')) trav = | |
mkTraversalsNP xs (trav . travZ) :* mkTraversalsNP2 xss (trav . travS) | |
travZ :: Trav (NS g (xs ': xss)) (g xs) | |
travZ f (Z here) = Z <$> f here | |
travZ f (S there) = pure (S there) | |
travS :: Trav (NS g (xs ': xss)) (NS g xss) | |
travS f (Z here) = pure (Z here) | |
travS f (S there) = S <$> f there | |
mkTraversalsNP :: forall s xs. NP Proxy xs -> Trav s (NP I xs) -> NP (Trav_ s) xs | |
mkTraversalsNP Nil _ = Nil | |
mkTraversalsNP ((x :: Proxy x) :* (xs :: NP Proxy xs')) trav = | |
Trav_ (trav . travHead . travI) :* mkTraversalsNP xs (trav . travTail) | |
travI :: Trav (I a) a | |
travI f (I x) = I <$> f x | |
travHead :: Trav (NP g (x ': xs)) (g x) | |
travHead f (x :* xs) = (:* xs) <$> f x | |
travTail :: Trav (NP g (x ': xs)) (NP g xs) | |
travTail f (x :* xs) = (x :*) <$> f xs | |
-- Example | |
data T = C0 | C1 Int | C2 Bool [()] | |
deriving (GHC.Generic, Generic) | |
POP | |
( Nil | |
:* (travC1 :* Nil) | |
:* (travC2_1 :* travC2_2 :* Nil) | |
:* Nil ) = mkTraversals @T | |
main :: IO () | |
main = pure () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment