LoginSignup
4
1

More than 5 years have passed since last update.

【解答例】Haskell アクションとラムダ 超入門

Last updated at Posted at 2014-12-03

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: *

中心極限定理により正規乱数を生成しています。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1