Created
June 17, 2013 09:56
-
-
Save SKoschnicke/5795863 to your computer and use it in GitHub Desktop.
Source for StackOverflow Question: Change element of list if it holds against some condition or add a new one if not, using Data.Lens (http://stackoverflow.com/questions/17087663)
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 TemplateHaskell, Rank2Types #-} | |
module ExampleForSO where | |
import Control.Lens | |
import Control.Applicative ((<$>), pure) | |
import Data.List (any) | |
data SomeRec = SomeRec { _name :: String, _val :: Int } | |
deriving (Show) | |
$(makeLenses ''SomeRec) | |
_find :: (a -> Bool) -> Simple Traversal [a] a | |
_find _ _ [] = pure [] | |
_find pred f (a:as) = if pred a | |
then (: as) <$> f a | |
else (a:) <$> (_find pred f as) | |
changeOrCreate :: [SomeRec] -> String -> (Int -> Int) -> [SomeRec] | |
changeOrCreate recs nameToSearch valModifier = | |
if (any (\r -> r^.name == nameToSearch) recs) | |
then over (_find (\r -> r^.name == nameToSearch)) (over val valModifier) recs | |
else recs ++ [SomeRec nameToSearch (valModifier 0)] | |
changeOrCreate' :: String -> (Int -> Int) -> [SomeRec] -> [SomeRec] | |
changeOrCreate' nameToSearch valModifier = | |
(pos nameToSearch) . val %~ valModifier | |
& outside (filtered (not . has (pos nameToSearch))) %~ (. newRec nameToSearch) | |
pos :: String -> Traversal' [SomeRec] SomeRec | |
pos nameToSearch = taking 1 (traversed . filtered (anyOf name (== nameToSearch))) | |
newRec nameToSearch = (SomeRec nameToSearch 0 :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment