Haskell State Monad示例

9bfwbjaz  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(106)

我正在尝试使用Haskell的Control.Monad.State,尝试遍历一个字符串或整数的列表,对它们进行计数,并将字符串条目替换为整数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

字符串

xyhw6mcr

xyhw6mcr1#

[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/traversestate来删除递归和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))

相关问题