次のようなものを書くことができます(お勧めしません)
output'' :: String -> IO String
output'' = fmap reverse . foldM parseChar []
where parseChar xs 'x' = putStrLn "'x' to upper" >> return ('X':xs)
parseChar xs 'y' = putStrLn "'y' to 'W'" >> return ('W':xs)
parseChar xs x = putStrLn "no transform" >> return ( x :xs)
出力あり
*Main> output'' "xyz"
'x' to upper
'y' to 'W'
no transform
"XWz"
しかし、For a Few Monad Moreから(Learn You a Haskell for Great Good!)
次のように書くことができます:
import Control.Monad.Writer
output :: String -> Writer [String] String
output [] = return []
output (x:xs) = do
xs' <- output xs
x' <- case x of
'x' -> tell ["'x' to upper"] >> return 'X'
'y' -> tell ["'y' to 'W'"] >> return 'W'
_ -> tell ["no transform"] >> return x
return (x':xs')
モナドを使用するとより柔軟になり、Writer を使用するとコードを純粋に実行できます (純粋であり、モナドのコンテキストとデータを処理する方法を制御できます。直接 IOoutput''
関数では制御できません)。
output
次のように関数を不純なコードに使用できます
main = do
input <- getLine
let (result, logging) = runWriter $ output input
putStrLn $ "Result: " ++ result
putStrLn $ unlines logging
実行中の出力は
*Main> main
hxdynx
Result: hXdWnX
'x' to upper
no transform
'y' to 'W'
no transform
'x' to upper
no transform
モナドを「foldM」のようなモナド関数と組み合わせることができます。
output' :: String -> Writer [String] String
output' = fmap reverse . foldM parseChar []
where parseChar xs 'x' = tell ["'x' to upper"] >> return ('X':xs)
parseChar xs 'y' = tell ["'y' to 'W'"] >> return ('W':xs)
parseChar xs x = tell ["no transform"] >> return ( x :xs)
(対数配列が逆)