
【해답 예】Haskell 액션과 람다 초입문
2022-10-04 last update
14 minutes reading 하스켈하스켈 액션과 람다 초입문 의 해답 예입니다.
셔플
셔플
【질문 1】 다음 코드에서 do
를 제거하고 >>=
로 연결하십시오.
import System.Random
shuffle [] = return []
shuffle xs =
(getStdRandom $ randomR (0, length xs - 1) :: IO Int) >>= \n ->
(shuffle $ take n xs ++ drop (n + 1) xs) >>= \xs' ->
return $ (xs !! n) : xs'
main =
shuffle [1..9] >>=
print
실행 결과(매번 다름)[3,5,4,9,2,7,8,6,1]
배열 업데이트
【질문 2】 배열에는 modifyIORef
에 상당하는 함수가 없습니다. modifyArray
를 구현해 주세요.
import Data.Array.IO
import Control.Applicative
modifyArray a i f = writeArray a i =<< f <$> readArray a i
main = do
a <- newArray (0, 2) 0 :: IO (IOUArray Int Int)
print =<< getElems a
modifyArray a 1 (+ 5)
print =<< getElems a
실행 결과[0,0,0]
[0,5,0]
재구성
【문3】 replicateM
, replicateM_
, forM
, forM_
, when
, unless
함수명에는 '
를 붙여 주세요.
import Control.Applicative
import System.Random
replicateM' 0 _ = return []
replicateM' n a | n > 0 = (:) <$> a <*> replicateM' (n - 1) a
replicateM_' 0 _ = return []
replicateM_' n a | n > 0 = a >> replicateM_' (n - 1) a
forM' [] _ = return []
forM' (x:xs) f = (:) <$> f x <*> forM' xs f
forM_' [] _ = return []
forM_' (x:xs) f = f x >> forM_' xs f
when' b a = if b then a else return ()
unless' b = when' $ not b
main = do
let dice = getStdRandom $ randomR (1, 6) :: IO Int
print =<< replicateM' 5 dice
putStrLn "---"
replicateM_' 3 $ do
print =<< dice
putStrLn "---"
a <- forM' [1..3] $ \i -> do
print i
return i
print a
putStrLn "---"
forM_' [1..3] $ \i -> do
print i
putStrLn "---"
let y f = f (y f)
y $ \f -> do
r <- dice
print r
when' (r /= 1) f
putStrLn "---"
y $ \f -> do
r <- dice
print r
unless' (r == 6) f
실행 결과(매번 다름)[4,3,2,5,1]
---
2
6
2
---
1
2
3
[1,2,3]
---
1
2
3
---
3
2
1
---
6
정규 난수
【문 4】0.0~1.0까지의 Double형의 난수를 12개 더한 것을 반올림하여 6을 뺀 정수치에 대해서, 100회의 분포를 구해 주세요. 반올림에는 round가 아니라 잘림 함수 truncate를 고안하여 사용하십시오.
import Control.Monad
import System.Random
rand :: IO Double
rand = getStdRandom $ randomR (0.0, 1.0)
main = do
r <- replicateM 100 $ do
rands <- replicateM 12 rand
return $ truncate (sum rands + 0.5) - 6
forM_ [-3 .. 3] $ \i -> do
let c = length $ filter (== i) r
i' = show i
n = replicate (2 - length i') ' ' ++ i'
putStrLn $ n ++ ": " ++ replicate c '*'
실행 결과(매번 다름)-3: *
-2: ******
-1: ****************************
0: **********************************
1: ***********************
2: *******
3: *
중심극한정리 에 의해 정규 난수 가 생성되었습니다.
import System.Random
shuffle [] = return []
shuffle xs =
(getStdRandom $ randomR (0, length xs - 1) :: IO Int) >>= \n ->
(shuffle $ take n xs ++ drop (n + 1) xs) >>= \xs' ->
return $ (xs !! n) : xs'
main =
shuffle [1..9] >>=
print
[3,5,4,9,2,7,8,6,1]
【질문 2】 배열에는
modifyIORef
에 상당하는 함수가 없습니다. modifyArray
를 구현해 주세요.import Data.Array.IO
import Control.Applicative
modifyArray a i f = writeArray a i =<< f <$> readArray a i
main = do
a <- newArray (0, 2) 0 :: IO (IOUArray Int Int)
print =<< getElems a
modifyArray a 1 (+ 5)
print =<< getElems a
실행 결과
[0,0,0]
[0,5,0]
재구성
【문3】 replicateM
, replicateM_
, forM
, forM_
, when
, unless
함수명에는 '
를 붙여 주세요.
import Control.Applicative
import System.Random
replicateM' 0 _ = return []
replicateM' n a | n > 0 = (:) <$> a <*> replicateM' (n - 1) a
replicateM_' 0 _ = return []
replicateM_' n a | n > 0 = a >> replicateM_' (n - 1) a
forM' [] _ = return []
forM' (x:xs) f = (:) <$> f x <*> forM' xs f
forM_' [] _ = return []
forM_' (x:xs) f = f x >> forM_' xs f
when' b a = if b then a else return ()
unless' b = when' $ not b
main = do
let dice = getStdRandom $ randomR (1, 6) :: IO Int
print =<< replicateM' 5 dice
putStrLn "---"
replicateM_' 3 $ do
print =<< dice
putStrLn "---"
a <- forM' [1..3] $ \i -> do
print i
return i
print a
putStrLn "---"
forM_' [1..3] $ \i -> do
print i
putStrLn "---"
let y f = f (y f)
y $ \f -> do
r <- dice
print r
when' (r /= 1) f
putStrLn "---"
y $ \f -> do
r <- dice
print r
unless' (r == 6) f
실행 결과(매번 다름)[4,3,2,5,1]
---
2
6
2
---
1
2
3
[1,2,3]
---
1
2
3
---
3
2
1
---
6
정규 난수
【문 4】0.0~1.0까지의 Double형의 난수를 12개 더한 것을 반올림하여 6을 뺀 정수치에 대해서, 100회의 분포를 구해 주세요. 반올림에는 round가 아니라 잘림 함수 truncate를 고안하여 사용하십시오.
import Control.Monad
import System.Random
rand :: IO Double
rand = getStdRandom $ randomR (0.0, 1.0)
main = do
r <- replicateM 100 $ do
rands <- replicateM 12 rand
return $ truncate (sum rands + 0.5) - 6
forM_ [-3 .. 3] $ \i -> do
let c = length $ filter (== i) r
i' = show i
n = replicate (2 - length i') ' ' ++ i'
putStrLn $ n ++ ": " ++ replicate c '*'
실행 결과(매번 다름)-3: *
-2: ******
-1: ****************************
0: **********************************
1: ***********************
2: *******
3: *
중심극한정리 에 의해 정규 난수 가 생성되었습니다.
import Control.Applicative
import System.Random
replicateM' 0 _ = return []
replicateM' n a | n > 0 = (:) <$> a <*> replicateM' (n - 1) a
replicateM_' 0 _ = return []
replicateM_' n a | n > 0 = a >> replicateM_' (n - 1) a
forM' [] _ = return []
forM' (x:xs) f = (:) <$> f x <*> forM' xs f
forM_' [] _ = return []
forM_' (x:xs) f = f x >> forM_' xs f
when' b a = if b then a else return ()
unless' b = when' $ not b
main = do
let dice = getStdRandom $ randomR (1, 6) :: IO Int
print =<< replicateM' 5 dice
putStrLn "---"
replicateM_' 3 $ do
print =<< dice
putStrLn "---"
a <- forM' [1..3] $ \i -> do
print i
return i
print a
putStrLn "---"
forM_' [1..3] $ \i -> do
print i
putStrLn "---"
let y f = f (y f)
y $ \f -> do
r <- dice
print r
when' (r /= 1) f
putStrLn "---"
y $ \f -> do
r <- dice
print r
unless' (r == 6) f
[4,3,2,5,1]
---
2
6
2
---
1
2
3
[1,2,3]
---
1
2
3
---
3
2
1
---
6
【문 4】0.0~1.0까지의 Double형의 난수를 12개 더한 것을 반올림하여 6을 뺀 정수치에 대해서, 100회의 분포를 구해 주세요. 반올림에는 round가 아니라 잘림 함수 truncate를 고안하여 사용하십시오.
import Control.Monad
import System.Random
rand :: IO Double
rand = getStdRandom $ randomR (0.0, 1.0)
main = do
r <- replicateM 100 $ do
rands <- replicateM 12 rand
return $ truncate (sum rands + 0.5) - 6
forM_ [-3 .. 3] $ \i -> do
let c = length $ filter (== i) r
i' = show i
n = replicate (2 - length i') ' ' ++ i'
putStrLn $ n ++ ": " ++ replicate c '*'
실행 결과(매번 다름)
-3: *
-2: ******
-1: ****************************
0: **********************************
1: ***********************
2: *******
3: *
중심극한정리 에 의해 정규 난수 가 생성되었습니다.