Skip to content

Instantly share code, notes, and snippets.

@Lysxia
Created October 1, 2020 15:51
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 Lysxia/f50ba99cdca1faa55dd598e707c0b594 to your computer and use it in GitHub Desktop.
Save Lysxia/f50ba99cdca1faa55dd598e707c0b594 to your computer and use it in GitHub Desktop.
{-# 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