Ivan
Ivan

Reputation: 95

Using State.modify from another function

It is only a skeleton of program. I have main function, that

State [Dec] [Dec]
mainCon = do
  acc <- get
  put []
  modify $ (++) [some func]
  return acc

On one stage I call function:

foldlWithKey'
                         (\list' key' val' ->
    if (...)
          then
                (Control.Monad.State.modify $ (Prelude.++) [elem]) >>
                some code
                : list')
          else
                (Control.Monad.State.modify $ (Prelude.++) []) >>
                some code
                : list')
                             )
                             []
                             (map')

and want to modify State in mainCon, but continue traverse map'. The error is:

No instance for (MonadState [Dec] [])
      arising from a use of ‘Control.Monad.State.modify’
    In the expression: Control.Monad.State.modify

[Dec] from Template Haskell. How can I simply solve this problem?

Upvotes: 0

Views: 134

Answers (1)

ErikR
ErikR

Reputation: 52029

Conceptually the problem is that the first argument passed to foldWithKey' must be a pure function, but when you use modify you are creating a stateful computation, not a pure function.

Apparently you are trying to iterate through a hashmap while maintaining some state during the traversal. foldWithKey' already gives you that state - it's the first parameter to the accumulation function:

                  v-- current state
foldlWithKey' :: (a -> k -> v -> a) -> a -> HashMap k v -> a
                     new state --^     ^-- initial         ^-- final
                                           state               state

The accumulation function takes the current state, a key and a value and returns an updated state. Then if you give foldWithKey' an initial state it will return the final state.

Here's an example using foldWithKey which is the same as foldWithKey' except that the arguments are in a slightly different order.

The functionevenOdds returns two lists - one containing the keys which have even values and those which have odd values.

The state is the pair (even,odds), and the accumulation function go returns the updated state based on the current key and value.

 {-# LANGUAGE NoMonomorphismRestriction #-}

 import qualified Data.HashMap as H

 myMap = H.fromList [ ("a",1), ("b",2), ("c",3), ("d",4) ]

 evenOdds :: ([String],[String])
 evenOdds = H.foldWithKey go ([],[]) myMap
   where  go :: String -> Int -> ([String],[String]) -> ([String],[String])
          go k a (evens,odds) = 
             if even a then ( evens ++ [k], odds)
                       else ( evens       , odds ++ [k] )

Upvotes: 1

Related Questions