ランダム性とI/O
getStdGen という I/O アクションは、何らかの初期データを使って システムのグローバル乱数ジェネレータを初期化する。
import System.Random main = do gen <- getStdGen putStrLn $ take 20 (randomRs ('a', 'z') gen)
実行
> stack ghc -- --make random_string.hs [1 of 1] Compiling Main ( random_string.hs, random_string.o ) Linking random_string ... > ./random_string pwmtcyvvuiqrlcxxugkg > ./random_string xgtscdkplkltwsviragk > ./random_string knqwbdakxwwngtwhfznj > ./random_string gaeihsegnztzrhktends
毎回違う値がとれている。
一度に2つのランダムな値が欲しいとする。
import System.Random main = do gen <- getStdGen putStrLn $ take 20 (randomRs ('a', 'z') gen) gen2 <- getStdGen putStrLn $ take 20 (randomRs ('a', 'z') gen2)
実行
> stack ghc -- --make random_string.hs [1 of 1] Compiling Main ( random_string.hs, random_string.o ) Linking random_string ... > ./random_string ogifizssaztchwbwaavl ogifizssaztchwbwaavl > ./random_string zyytwpyywogfjmtolvjm zyytwpyywogfjmtolvjm > ./random_string lopqapxwdkakjuipcgfv lopqapxwdkakjuipcgfv
getStdGen を2回実行しても同じグローバル乱数ジェネレータをシステムが 返してくるのでこれではダメ。
これを実現するためには、newStdGen アクションを使う。 これはグローバル乱数ジェネレータを2つのジェネレータに分割する。
import System.Random main = do gen <- getStdGen putStrLn $ take 20 (randomRs ('a', 'z') gen) gen' <- newStdGen putStrLn $ take 20 (randomRs ('a', 'z') gen')
実行
> stack ghc -- --make random_string.hs [1 of 1] Compiling Main ( random_string.hs, random_string.o ) Linking random_string ... > ./random_string wxyevwiruiwsoqwyabdr uwcvveeltuejritxceih > ./random_string zjqgfnuekjdaelehlxvj goefmqrrebmzmqsiomao > ./random_string enxgkrluzhbyqoxhqssr klekqhhqszulpjsntjsl
できた。
newStdGen を束縛すると、新しい乱数ジェネレータが 得られるだけでなく、グローバルジェネレータも更新される。
ユーザーにプログラムが考えた数を当てさせるプログラムを書く
import System.Random import Control.Monad(when) main = do gen <- getStdGen askForNumber gen askForNumber :: StdGen -> IO () askForNumber gen = do let (randNumber, newGen) = randomR (1,10) gen :: (Int, StdGen) putStrLn "Which number in the range from 1 to 10 am I thinking of? " numberString <- getLine when (not $ null numberString) $ do let number = read numberString if randNumber == number then putStrLn "You are correct." else putStrLn $ "Sorry, it was " ++ show randNumber askForNumber newGen
実行
> stack ghc -- --make guess_the_number.hs [1 of 1] Compiling Main ( guess_the_number.hs, guess_the_number.o ) Linking guess_the_number ... > ./guess_the_number Which number in the range from 1 to 10 am I thinking of? 1 Sorry, it was 7 Which number in the range from 1 to 10 am I thinking of? 2 Sorry, it was 5 Which number in the range from 1 to 10 am I thinking of? 3 Sorry, it was 1 Which number in the range from 1 to 10 am I thinking of? 4 Sorry, it was 1 Which number in the range from 1 to 10 am I thinking of? 5 Sorry, it was 6 Which number in the range from 1 to 10 am I thinking of? 6 Sorry, it was 9 Which number in the range from 1 to 10 am I thinking of? 7 Sorry, it was 6 Which number in the range from 1 to 10 am I thinking of? 5 Sorry, it was 10 Which number in the range from 1 to 10 am I thinking of? 3 Sorry, it was 9 Which number in the range from 1 to 10 am I thinking of? 2 Sorry, it was 1 Which number in the range from 1 to 10 am I thinking of? 1 Sorry, it was 5 Which number in the range from 1 to 10 am I thinking of? 2 Sorry, it was 10 Which number in the range from 1 to 10 am I thinking of? 3 Sorry, it was 7 Which number in the range from 1 to 10 am I thinking of? 4 Sorry, it was 5 Which number in the range from 1 to 10 am I thinking of? 5 Sorry, it was 10 Which number in the range from 1 to 10 am I thinking of? 6 You are correct.
なかなか当たらん。
所感
let number = read numberString
でなんで数字に変換されるのか調べる。
デフォルトで文字列 -> 数値 の変換になるのかドキュメントのどこに書いてあるかわからん。
追記
型推論っぽい
Haskell の read 関数で、文字列から代数的データ型へ変換 - 導出インスタンスを使って | すぐに忘れる脳みそのためのメモ

- 作者: MiranLipovaca
- 出版社/メーカー: オーム社
- 発売日: 2017/07/14
- メディア: Kindle版
- 購入: 4人 クリック: 9回
- この商品を含むブログを見る