You just tweak it and shuffle a few words around, like
foo (list) =
-- int somestate
-- foreach list as item
-- foreach item in list
do item <- list
if item == 1
then return incr -- state
else return decr -- state
-- return state
incr state = state + 1
decr state = state - 1
and already get yourself a thing, with a type deduced for it! which is
foo :: (Num a, Num b, Monad m, Eq a) => m a -> m (b -> b)
We know m ~ [] so it's actually
foo :: (Num a1, Num a, Eq a) => [a] -> [b -> b]
So, what can we do with the bunch of state-updating functions, like incr/decr, in a row? A couple of things:
import Control.Monad
import Data.Monoid
import Data.Foldable
sequence . foo :: (Num a, Num b, Eq a) => [a] -> b -> [b]
foldr (.) id . foo :: (Num a, Num b, Eq a) => [a] -> b -> b
appEndo . foldMap Endo . foo
:: (Num a, Num b, Eq a) => [a] -> b -> b
foldl (.) id . foo :: (Num a, Num b, Eq a) => [a] -> b -> b
appEndo . getDual . foldMap (Dual . Endo) . foo
:: (Num a, Num b, Eq a) => [a] -> b -> b
Not the first one, certainly.
It would seem that the one with foldl is the ticket here. But then again, it goes against non sunt multiplicanda praeter necessitatem. So really, it's
foo :: (Num t, Num a, Eq a) => [a] -> t -> t
foo = foldr g id
where
g x r state | x==1 = r (incr state) -- or even `r $! incr state`
| otherwise = r (decr state) -- `r $! decr state`
or simpler,
foo :: (Num t, Num a, Eq a) => [a] -> t -> t
foo = foldr g id
where
g x r | x==1 = r . incr
| otherwise = r . decr
or even just
foo :: (Num t, Num a, Eq a) => [a] -> t -> t
foo = foldr (\x -> if x==1 then (. incr) else (. decr)) id
which actually is the one with the Dual we had all along. I think. Have fun validating this (or otherwise). :)
update: Fusing foldr (.) id . foo into one function leads to an even nicer looking
foo :: (Num t, Num a, Eq a) => [a] -> t -> t
foo = flip $ foldr (\x -> if x==1 then incr else decr)
but it processes the state in the opposite order.