Skip to content

Instantly share code, notes, and snippets.

@SKoschnicke
Created June 17, 2013 09:56
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 SKoschnicke/5795863 to your computer and use it in GitHub Desktop.
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)
{-# 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