
【해답 예】Haskell 모나드 변환자 초입문
2022-10-04 last update
17 minutes reading 하스켈Haskell 모나드 변환기 초입문 의 해답 예입니다.
State 모나드
State 모나드
【문 1】State 모나드를 다루는 return
를 StateT
를 사용해, runState
를 runStateT
import Control.Monad.Identity
import Control.Monad.State hiding (return, runState)
return' x = StateT $ \s -> Identity (x, s)
runState' st = runIdentity . runStateT st
main = do
let st = return' 1
print $ runState' st ()
실행 결과(1,())
Identity 모나드가 끼여 있음을 의식합니다.
StateT 모나드 변환기
재구성
【문 2】StateT 모나드 변환자를 다루는 bind
, get
, modify
, lift
를 구현해 주세요. do
는 사용하지 마십시오. >>=
는 StateT 모나드 변환자 이외에만 사용하십시오.
import Control.Monad
import Control.Monad.State hiding (get, modify, lift)
a `bind` b = StateT $ \s ->
runStateT a s >>= \(r, s1) ->
runStateT (b r) s1
get = StateT $ \s -> return (s, s)
modify f = StateT $ \s -> return ((), f s)
lift m = StateT $ \s -> m >>= \a -> return (a, s)
fact x = (`execStateT` 1) $
forM_ [1..x] $ \i ->
modify (* i) `bind` \_ ->
get `bind` \v ->
lift $ putStrLn $ "*" ++ show i ++ " -> " ++ show v
main = fact 5 >>= print
실행 결과*1 -> 1
*2 -> 2
*3 -> 6
*4 -> 24
*5 -> 120
()
다시 작성
【문 3】문 2의 fact
를 do
와 <-
질문 2에서 다시 구현한 함수는 사용하지 마십시오.
import Control.Monad
import Control.Monad.State
fact x = (`execStateT` 1) $ do
forM_ [1..x] $ \i -> do
modify (* i)
v <- get
lift $ putStrLn $ "*" ++ show i ++ " -> " ++ show v
main = fact 5 >>= print
실행 결과*1 -> 1
*2 -> 2
*3 -> 6
*4 -> 24
*5 -> 120
()
모나드 변환기로 합성
Maybe 모나드
【질문 4】다음의 코드는 종류를 판별하면서 캐릭터 라인을 읽어 진행하는 것을 의도하고 있습니다. Maybe 모나드를 사용하여 오류가 발생하지 않도록 수정합니다. 모나드 변환자는 사용하지 마십시오.
import Data.Char
getch f (x:xs) | f x = Just (x, xs)
getch _ _ = Nothing
test s0 = do
(ch1, s1) <- getch isUpper s0
(ch2, s2) <- getch isLower s1
(ch3, s3) <- getch isDigit s2
return [ch1, ch2, ch3]
main = do
print $ test "Aa0"
print $ test "abc"
Just "Aa0"
Nothing
StateT 모나드 변환기
【문5】문4의 해답을 StateT 모나드 변환자를 사용해 재작성해 주세요.
import Data.Char
import Control.Monad.State
getch f = StateT getch where
getch (x:xs) | f x = Just (x, xs)
getch _ = Nothing
test = evalStateT $ do
ch1 <- getch isUpper
ch2 <- getch isLower
ch3 <- getch isDigit
return [ch1, ch2, ch3]
main = do
print $ test "Aa0"
print $ test "abc"
Just "Aa0"
Nothing
다른 모나드 변환기
【질문 6】다음 코드의 print
를 main
에서 각 test*
실행 결과가 동일하도록 조정하십시오.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
lift $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
lift $ print $ x + 1
testL x = runListT $ do
lift $ print [x + 1]
main = do
testR 0
testW 0
testL 0
실행 결과1
1
[1]
모나드 변환기의 평가 결과가 IO 모나드에서 반환되기 때문에 do
에 직접 기술할 수 있습니다.
liftIO
【문 7】문 6을 main
로 풀어 주십시오.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
liftIO $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
liftIO $ print $ x + 1
testL x = runListT $ do
liftIO $ print [x + 1]
main = do
testR 0
testW 0
testL 0
실행 결과1
1
[1]
liftM
【문8】 다음의 리스트내포 표기를 liftIO
계의 함수로 재작성해 주세요.
import Control.Monad
main = do
print $ liftM2 (,) [0, 1] [0, 2]
print $ liftM2 (+) [0, 1] [0, 2]
실행 결과[(0,0),(0,2),(1,0),(1,2)]
[0,2,1,3]
liftM
그냥 움직임을 알기 어렵기 때문에 (+)
와 비교해 보세요.
import Control.Monad.Identity
import Control.Monad.State hiding (return, runState)
return' x = StateT $ \s -> Identity (x, s)
runState' st = runIdentity . runStateT st
main = do
let st = return' 1
print $ runState' st ()
(1,())
재구성
【문 2】StateT 모나드 변환자를 다루는
bind
, get
, modify
, lift
를 구현해 주세요. do
는 사용하지 마십시오. >>=
는 StateT 모나드 변환자 이외에만 사용하십시오.import Control.Monad
import Control.Monad.State hiding (get, modify, lift)
a `bind` b = StateT $ \s ->
runStateT a s >>= \(r, s1) ->
runStateT (b r) s1
get = StateT $ \s -> return (s, s)
modify f = StateT $ \s -> return ((), f s)
lift m = StateT $ \s -> m >>= \a -> return (a, s)
fact x = (`execStateT` 1) $
forM_ [1..x] $ \i ->
modify (* i) `bind` \_ ->
get `bind` \v ->
lift $ putStrLn $ "*" ++ show i ++ " -> " ++ show v
main = fact 5 >>= print
실행 결과
*1 -> 1
*2 -> 2
*3 -> 6
*4 -> 24
*5 -> 120
()
다시 작성
【문 3】문 2의
fact
를 do
와 <-
질문 2에서 다시 구현한 함수는 사용하지 마십시오.import Control.Monad
import Control.Monad.State
fact x = (`execStateT` 1) $ do
forM_ [1..x] $ \i -> do
modify (* i)
v <- get
lift $ putStrLn $ "*" ++ show i ++ " -> " ++ show v
main = fact 5 >>= print
실행 결과
*1 -> 1
*2 -> 2
*3 -> 6
*4 -> 24
*5 -> 120
()
모나드 변환기로 합성
Maybe 모나드
【질문 4】다음의 코드는 종류를 판별하면서 캐릭터 라인을 읽어 진행하는 것을 의도하고 있습니다. Maybe 모나드를 사용하여 오류가 발생하지 않도록 수정합니다. 모나드 변환자는 사용하지 마십시오.
import Data.Char
getch f (x:xs) | f x = Just (x, xs)
getch _ _ = Nothing
test s0 = do
(ch1, s1) <- getch isUpper s0
(ch2, s2) <- getch isLower s1
(ch3, s3) <- getch isDigit s2
return [ch1, ch2, ch3]
main = do
print $ test "Aa0"
print $ test "abc"
Just "Aa0"
Nothing
StateT 모나드 변환기
【문5】문4의 해답을 StateT 모나드 변환자를 사용해 재작성해 주세요.
import Data.Char
import Control.Monad.State
getch f = StateT getch where
getch (x:xs) | f x = Just (x, xs)
getch _ = Nothing
test = evalStateT $ do
ch1 <- getch isUpper
ch2 <- getch isLower
ch3 <- getch isDigit
return [ch1, ch2, ch3]
main = do
print $ test "Aa0"
print $ test "abc"
Just "Aa0"
Nothing
다른 모나드 변환기
【질문 6】다음 코드의 print
를 main
에서 각 test*
실행 결과가 동일하도록 조정하십시오.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
lift $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
lift $ print $ x + 1
testL x = runListT $ do
lift $ print [x + 1]
main = do
testR 0
testW 0
testL 0
실행 결과1
1
[1]
모나드 변환기의 평가 결과가 IO 모나드에서 반환되기 때문에 do
에 직접 기술할 수 있습니다.
liftIO
【문 7】문 6을 main
로 풀어 주십시오.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
liftIO $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
liftIO $ print $ x + 1
testL x = runListT $ do
liftIO $ print [x + 1]
main = do
testR 0
testW 0
testL 0
실행 결과1
1
[1]
liftM
【문8】 다음의 리스트내포 표기를 liftIO
계의 함수로 재작성해 주세요.
import Control.Monad
main = do
print $ liftM2 (,) [0, 1] [0, 2]
print $ liftM2 (+) [0, 1] [0, 2]
실행 결과[(0,0),(0,2),(1,0),(1,2)]
[0,2,1,3]
liftM
그냥 움직임을 알기 어렵기 때문에 (+)
와 비교해 보세요.
import Data.Char
getch f (x:xs) | f x = Just (x, xs)
getch _ _ = Nothing
test s0 = do
(ch1, s1) <- getch isUpper s0
(ch2, s2) <- getch isLower s1
(ch3, s3) <- getch isDigit s2
return [ch1, ch2, ch3]
main = do
print $ test "Aa0"
print $ test "abc"
Just "Aa0"
Nothing
import Data.Char
import Control.Monad.State
getch f = StateT getch where
getch (x:xs) | f x = Just (x, xs)
getch _ = Nothing
test = evalStateT $ do
ch1 <- getch isUpper
ch2 <- getch isLower
ch3 <- getch isDigit
return [ch1, ch2, ch3]
main = do
print $ test "Aa0"
print $ test "abc"
Just "Aa0"
Nothing
【질문 6】다음 코드의
print
를 main
에서 각 test*
실행 결과가 동일하도록 조정하십시오.import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
lift $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
lift $ print $ x + 1
testL x = runListT $ do
lift $ print [x + 1]
main = do
testR 0
testW 0
testL 0
실행 결과
1
1
[1]
모나드 변환기의 평가 결과가 IO 모나드에서 반환되기 때문에
do
에 직접 기술할 수 있습니다.liftIO
【문 7】문 6을 main
로 풀어 주십시오.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
liftIO $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
liftIO $ print $ x + 1
testL x = runListT $ do
liftIO $ print [x + 1]
main = do
testR 0
testW 0
testL 0
실행 결과1
1
[1]
liftM
【문8】 다음의 리스트내포 표기를 liftIO
계의 함수로 재작성해 주세요.
import Control.Monad
main = do
print $ liftM2 (,) [0, 1] [0, 2]
print $ liftM2 (+) [0, 1] [0, 2]
실행 결과[(0,0),(0,2),(1,0),(1,2)]
[0,2,1,3]
liftM
그냥 움직임을 알기 어렵기 때문에 (+)
와 비교해 보세요.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.List
testR x = (`runReaderT` x) $ do
a <- ask
liftIO $ print $ a + 1
testW x = runWriterT $ do
tell $ show x
liftIO $ print $ x + 1
testL x = runListT $ do
liftIO $ print [x + 1]
main = do
testR 0
testW 0
testL 0
1
1
[1]
【문8】 다음의 리스트내포 표기를
liftIO
계의 함수로 재작성해 주세요.import Control.Monad
main = do
print $ liftM2 (,) [0, 1] [0, 2]
print $ liftM2 (+) [0, 1] [0, 2]
실행 결과
[(0,0),(0,2),(1,0),(1,2)]
[0,2,1,3]
liftM
그냥 움직임을 알기 어렵기 때문에 (+)
와 비교해 보세요.