【해답 예】Haskell 액션과 람다 초입문

【해답 예】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: *

중심극한정리 에 의해 정규 난수 가 생성되었습니다.