Haskell アクションとラムダ 超入門の解答例です。
シャッフル
【問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: *