Last active
April 23, 2025 07:15
-
-
Save mistivia/c7a805cf35e46e045a094a9bf2c362ed to your computer and use it in GitHub Desktop.
Simple yet usable lens-like utility functions to access nested record fileds in haskell
This file contains hidden or 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
| -- The Library | |
| accessor getter setter f x = (setter newVal x, getter x) where newVal = f (getter x) | |
| get accessor x = snd $ accessor id x | |
| set accessor f x = fst $ accessor f x | |
| composeAccessors ac1 ac2 modifier obj = | |
| (newObj, value) | |
| where | |
| newObj = fst $ ac1 innerModifier obj | |
| innerModifier innerObj = fst $ ac2 modifier innerObj | |
| value = get ac2 (get ac1 obj) | |
| composeFunctorAccesors ac1 ac2 modifier obj = | |
| (newObj, value) | |
| where | |
| newObj = fst $ ac1 (fmap innerModifier) obj | |
| innerModifier innerObj = fst $ ac2 modifier innerObj | |
| value = fmap (get ac2) (get ac1 obj) | |
| infixr 5 #. | |
| (#.) = composeAccessors | |
| infixr 5 ##. | |
| (##.) :: (Functor f1, Functor f0) => | |
| ((f1 a1 -> f1 a1) -> t -> (a2, f0 a1)) | |
| -> ((a3 -> a3) -> a1 -> (a1, b)) -> | |
| (a3 -> a3) -> t -> (a2, f0 b) | |
| (##.) = composeFunctorAccesors | |
| self = accessor id (\n x -> n) | |
| data Person = Person | |
| { _name :: String | |
| , _address :: Maybe Address | |
| } deriving (Show) | |
| name = accessor _name (\n x -> x {_name = n}) | |
| address = accessor _address (\n x -> x {_address = n}) | |
| data Address = Address | |
| { _city :: String | |
| , _zipInfos :: [Maybe ZipInfo] | |
| } deriving (Show) | |
| city = accessor _city (\n x -> x {_city = n}) | |
| zipInfos = accessor _zipInfos (\n x -> x {_zipInfos = n}) | |
| data ZipInfo = ZipInfo | |
| { _code :: String | |
| , _extraInfo :: Maybe String | |
| } deriving (Show) | |
| code = accessor _code (\n x -> x {_code = n}) | |
| extraInfo = accessor _extraInfo (\n x -> x {_extraInfo = n}) | |
| alice = Person | |
| { _name = "Alice" | |
| , _address = Just Address | |
| { _city = "Shanghai" | |
| , _zipInfos = | |
| [ Just ZipInfo | |
| { _code = "200000" | |
| , _extraInfo = Nothing | |
| } | |
| , Just ZipInfo | |
| { _code = "200002" | |
| , _extraInfo = Nothing | |
| } | |
| ] | |
| } | |
| } | |
| listAt idx = accessor (head . drop idx) (\n lst -> (take idx lst) ++ [n] ++ (drop (idx + 1) lst)) | |
| setList = | |
| set (listAt 1 #. listAt 1) (const 5) [[1,2],[3,4]] | |
| main = do | |
| putStrLn . show $ setList | |
| putStrLn . show $ alice | |
| putStrLn . show $ get (name) alice | |
| putStrLn . show $ get (address ##. city) alice | |
| putStrLn . show $ get (address ##. zipInfos ##. self ##. code) alice | |
| putStrLn . show $ set (address ##. zipInfos ##. self ##. code) (++ "uwu") alice | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment