Reputation: 4085
I'm just in the process of learning haskell and I am sure that an elegant solution to the following problem exists. Given a function f that returns a stateful computation
f :: (Num a) => a -> a -> State [a] a
f x y = modify ((2*x):) >> return (x+y) -- state and value are modified based on the passed values
I am looking for the cleanest way to generate multiple State
's from a given one recursively (as shown below). One solution I came up with is the following
g :: (Num a) => [a] -> (a, [a]) -> [(a,[a])]
g [] _ = []
g (x:xs) aa@(a,b) = (new : next)
where new = runState (f x a) b -- here the old value a is required!
next = g xs aa
but I guess something like
g :: [a] -> [State [a] a]
should be possible and cleaner? I didn't succeed trying this and get errors from StateT that I can't figure out.
Thank you!
Background: The code is a simplification of parts of a graph generator I am writing, where the state is the current adjacency vector. For each node, several edges may be created and therefore multiple state is required representing the different (partial) graphs.
Edit: (Try of) A description in words of the above function g x (y, s)
in words:
For a given list of values x
, a single value y
and a state s
, compute recursively for each x_i
in x
a new value and state from (y,s)
given by the stateful computation f x_i y
and return the result as a list.
Edit 2: Example output:
g [1,2,3] (4,[2,3,4]) == [(5,[10,2,3,4]),(6,[12,2,3,4]),(7,[14,2,3,4])]
Upvotes: 4
Views: 222
Reputation: 2354
Here are some iterative changes to your g
function. I hope this is what you were looking for, because I am not sure I fully understand what you tried to achieve:
Your original g:
g :: Num a => [a] -> a -> [a] -> [(a,[a])]
g [] _ _ = []
g (x:xs) a b = new : next
where
new = runState (f (h x a)) b -- here the old value a is required!
next = g xs a b
Points-free:
g1 :: Num a => [a] -> a -> [a] -> [(a,[a])]
g1 xs a b = map (($ b) . runState . f . (`h` a)) $ xs
Flip for ETA reducability:
g2 :: Num a => [a] -> a -> [a] -> [(a,[a])]
g2 b a = map (($ b) . runState . f . (`h` a))
Without the ($ b) . runState
application (no need for the extra [a] argument since we don't apply the State computations):
g3 :: Num a => a -> [a] -> [State [a] a]
g3 a = map (f . (`h` a))
The map there can also be written:
map f . map (`h` a)
and then you can take the
map (\`h\` a)
part out somewhere else.
This gives you something similar to the type you wanted for g
, and of course changes the semantics (as that type is still unapplied to the input state)
Upvotes: 3