问题描述
我现在正在学习 Haskell,我正在尝试与状态 Monad 合作。
我递归地要求用户输入并将其附加到列表中。当我在同一个函数中实现 IO 处理和状态执行时,程序按预期工作:
picture_count
由于我不明白的原因,当我将状态处理函数与 IO 函数分开时,返回的状态是用一个列表包装的:
import Control.Monad.State
push :: String -> State [String] ()
push a = state $ \xs -> ((),a:xs)
testingState :: State [String] ()
testingState = do
push ("testing state!")
return ()
handleState :: [String] -> IO()
handleState prevIoUsstack = do
line <- getLine
let userIntput = words line
let stack = userIntput ++ prevIoUsstack
let newStack = (execState testingState) stack
handleState newStack
main :: IO
main = do
handleState []
handleState :: [String] -> IO()
handleState prevIoUsstack = do
line <- getLine
let newStack = changeState line stack
handleState newStack
changeState :: String -> [String] -> [String]
changeState line prevIoUsstack = do
let userIntput = words line
let stack = userIntput ++ prevIoUsstack
let newStack = (execState testingState) stack
return newStack
main = do
handleState []
另外,我只能在 • Couldn't match type ‘[Char]’ with ‘Char’
Expected type: [String]
Actual type: [[String]]
函数外部展平数组,在函数内部这样做是行不通的。
解决方法
您在 do
中使用了 return
和 changeState
。由于 do
块的类型是 [String]
,它将使用 Monad
类型类的列表实例,这意味着 return :: Monad m => a -> m a
将包装一个元素在列表中。
您可以将 changeState
函数实现为:
changeState :: String -> [String] -> [String]
changeState line previousStack = execState testingState (words line ++ previousStack)