The Haskell types and the logic of your JavaScript code doesn't match: the JS code has two values in the state (the Int, and the returned list). In contrast, StateT Int [] a
doesn't really have a list in the state; rather, it runs stateful actions multiple times (with the initial state unchanged for each run) and collects all the results in a list.
In other words, the JS code has type State (Int, [(Int, Int)]) [(Int, Int)]
. But this is too literal a translation and we can write more elegant Haskell code.
Sticking to the State
monad, we can return a list with mapM
or forM
:
test2 :: Int -> [(Int, Int)]
test2 = evalState $
forM [1..10] $ \a -> do
s <- get <* modify (+a)
return (a, s)
Some lens
magic can make it more similar to the JS code:
{-# LANGUAGE TupleSections #-}
import Control.Lens
test3 :: Int -> [(Int, Int)]
test3 = evalState $
forM [1..10] $ \a -> (a,) <$> (id <+= a)
However, we can do away with State
altogether, and it's the best approach here, I think:
import Control.Monad (ap)
test4 :: Int -> [(Int, Int)]
test4 n = ap zip (tail . scanl (+) n) [1..10]
-- or without ap : zip [1..10] (drop 1 $ scanl (+) n [1..10])