1 {-# LANGUAGE DataKinds #-}
2 {-# LANGUAGE DeriveGeneric #-}
3 {-# LANGUAGE FlexibleContexts #-}
5 {-# LANGUAGE ScopedTypeVariables #-}
6 import qualified GHC
.Generics
as GHC
7 import Data
.Char (toLower)
8 import Data
.List
(stripPrefix
)
11 import Generics
.SOP
.GGP
13 -- | An example of generic deriving of lens code.
15 -- >>> putStrLn $ genericLenses (Proxy :: Proxy Foobar)
16 -- fooBar :: Lens' Foobar Int
17 -- fooBar f s = fmap (\x -> s { T.fooBar = x }) (T.fooBar s)
18 -- {-# INLINE fooBar #-}
20 -- fooXyzzy :: Lens' Foobar [[Char]]
21 -- fooXyzzy f s = fmap (\x -> s { T.fooXyzzy = x }) (T.fooXyzzy s)
22 -- {-# INLINE fooXyzzy #-}
25 -- /Note:/ 'FilePath' i.e @type@ aliases are lost.
29 , fooXyzzy
:: [FilePath]
32 deriving (GHC
.Generic
)
35 :: forall a xs proxy
. (GDatatypeInfo a
, GCode a ~
'[xs
], All Typeable xs
)
38 genericLenses p
= case gdatatypeInfo p
of
39 Newtype _ _ _
-> "-- newtype deriving not implemented"
40 ADT _ _
(Constructor _
:* Nil
) -> "-- fieldnameless deriving not implemented"
41 ADT _ _
(Infix _ _ _
:* Nil
) -> "-- infix constructor deriving not implemented"
42 ADT _ dn
(Record _ fis
:* Nil
) ->
43 unlines $ concatMap replaceTypes
$ hcollapse
$ hcmap
(Proxy
:: Proxy Typeable
) derive fis
45 derive
:: forall x
. Typeable x
=> FieldInfo x
-> K
[String] x
46 derive
(FieldInfo fi
) = K
47 [ fi
++ " :: Lens' " ++ dn
++ " " ++ showsPrec 11 (typeRep
(Proxy
:: Proxy x
)) []
48 , fi
++ " f s = fmap (\\x -> s { T." ++ fi
++ " = x }) (f (T." ++ fi
++ " s))"
49 , "{-# INLINE " ++ fi
++ " #-}"
54 :: forall a xs proxy
. (GDatatypeInfo a
, GCode a ~
'[xs
], All Typeable xs
)
57 genericClassyLenses p
= case gdatatypeInfo p
of
58 Newtype _ _ _
-> "-- newtype deriving not implemented"
59 ADT _ _
(Constructor _
:* Nil
) -> "-- fieldnameless deriving not implemented"
60 ADT _ _
(Infix _ _ _
:* Nil
) -> "-- infix constructor deriving not implemented"
61 ADT _ dn
(Record _ fis
:* Nil
) ->
62 unlines $ concatMap replaceTypes
$
63 [[ "class Has" ++ dn
++ " a where"
64 , " " ++ dn
' ++ " :: Lens' a " ++ dn
67 (hcollapse
$ hcmap
(Proxy
:: Proxy Typeable
) deriveCls fis
) ++
69 , "instance Has" ++ dn
++ " " ++ dn
++ " where"
70 , " " ++ dn
' ++ " = id"
71 , " {-# INLINE " ++ dn
' ++ " #-}"
73 (hcollapse
$ hcmap
(Proxy
:: Proxy Typeable
) deriveInst fis
)
77 c
:cs
-> toLower c
: cs
79 deriveCls
:: forall x
. Typeable x
=> FieldInfo x
-> K
[String] x
80 deriveCls
(FieldInfo fi
) = K
81 [ " " ++ fi
++ " :: Lens' a " ++ showsPrec 11 (typeRep
(Proxy
:: Proxy x
)) []
82 , " " ++ fi
++ " = " ++ dn
' ++ " . " ++ fi
83 , " {-# INLINE " ++ fi
++ " #-}"
87 deriveInst
:: forall x
. Typeable x
=> FieldInfo x
-> K
[String] x
88 deriveInst
(FieldInfo fi
) = K
89 [ " " ++ fi
++ " f s = fmap (\\x -> s { T." ++ fi
++ " = x }) (f (T." ++ fi
++ " s))"
90 , " {-# INLINE " ++ fi
++ " #-}"
94 replaceTypes
:: [String] -> [String]
96 $ replace
"[Char]" "String"
98 replace
:: String -> String -> String -> String
99 replace needle replacement
= go
where
102 | Just ys
<- stripPrefix needle xs
= replacement
++ go ys
103 |
otherwise = x
: go xs
'