我试图通过字符串或整数列表进行迭代,计数他们,并与整数Control.Monad.State
替换字符串项与Haskell的0
试验。我已成功地执行计数的一部分,但在创建替代列表失败。这里是我的代码正确打印[3,6]
到屏幕上。我怎样才能使创建所需的列表[6,0,3,8,0,2,9,1,0]
?
module Main( main ) where
import Control.Monad.State
l = [
Right 6,
Left "AAA",
Right 3,
Right 8,
Left "CCC",
Right 2,
Right 9,
Right 1,
Left "D"]
scanList :: [ Either String Int ] -> State (Int,Int) [ Int ]
scanList [ ] = do
(ns,ni) <- get
return (ns:[ni])
scanList (x:xs) = do
(ns,ni) <- get
case x of
Left _ -> put (ns+1,ni)
Right _ -> put (ns,ni+1)
case x of
Left _ -> scanList xs -- [0] ++ scanList xs not working ...
Right i -> scanList xs -- [i] ++ scanList xs not working ...
startState = (0,0)
main = do
print $ evalState (scanList l) startState
[0] ++ scanList xs
不起作用,因为scanList xs
是不是列表,而是一个State (Int,Int) [Int]
。为了解决这个问题,你将需要使用fmap
/ <$>
。
您还需要改变基本情况不使状态值是返回值。
scanList :: [Either String Int] -> State (Int, Int) [Int]
scanList [] = return []
scanList (x:xs) = do
(ns,ni) <- get
case x of
Left _ -> put (ns+1, ni)
Right _ -> put (ns, ni+1)
case x of
Left _ -> (0 :) <$> scanList xs
Right i -> (i :) <$> scanList xs
为了进一步简化代码,但是,这将是很好用mapM
/ traverse
和state
除去大部分递归和get
/ put
语法的样板。
scanList :: [Either String Int] -> State (Int, Int) [Int]
scanList = mapM $ \x -> state $ \(ns, ni) -> case x of
Left _ -> (0, (ns+1, ni))
Right i -> (i, (ns, ni+1))