Search code examples
haskellmonadsstate-monad

State Monad: Modifying state without modifying value


I am writing a function that takes a predicate p and a list. It returns ([value],[state]) where the first list contains elements that pass p and the second contains the elements that do not. However, when I run

runState (myFunc even [1,2,3,4,5]) [] 

I get ([2,4,5,3,1],[5,3,1]) where the failed elements are incorrectly being stored in [value]. I believe this is due to get updating both state and value, but I haven't been able to find a way to update just the state and leave the value alone so I was wondering how I would do that.

myFunc :: (a->Bool) -> [a] -> State [a] [a]
myFunc _ [] = do
  a <- get
  return a
myFunc p (x:xs) = do
    if (p x) then do
      s <- myFunc p xs
      let ret = (x:s)
      return ret
    else do
      s <- get
      put(x:s)
      myFunc p xs

Solution

  • Your myFunc _ [] definition is indeed putting the state into the value. You actually just want it to be an empty list of passes:

    myFunc _ [] = return []
    

    and then you probably want to return the results in order:

    myFunc :: (a -> Bool) -> [a] -> State [a] [a]
    myFunc _ [] = return []
    myFunc p (x:xs) = do
        passes <- myFunc p xs
    
        if p x then
            return (x:passes)
        else do
            modify (x:)
            return passes
    

    side cool way to write it even though it’s probably an exercise in state and partition already exists,

    import Data.Bifunctor
    
    partition f = foldr m ([], [])
        where m x = (if f x then first else second) (x:)