まず、コードを少しクリーンアップしましょう。randomRランダム値の無限リストを提供するの複数形バージョンがあります: randomRs. これは物事を少し単純化します:
rndPoints1 :: [String] -> [Point]
rndPoints1 [] = []
rndPoints1 xs = zip x y
where
size = length xs
x = take size $ randomRs (25, 1000) (mkStdGen 1)
y = take size $ randomRs (25, 775) (mkStdGen 1)
zip短いリストが使い果たされた後に停止する のプロパティを使用することで、それをさらに単純化できます。
rndPoints2 :: [a] -> [Point]
rndPoints2 xs = map snd $ zip xs $ zip x y
where
x = randomRs (25, 1000) (mkStdGen 1)
y = randomRs (25, 775) (mkStdGen 1)
また、受信リストのタイプを単に に一般化したことに注意してください[a]。値は使用されないため、s である必要はありませんString。
mkStdGenこれで、毎回同じシード ( ) から疑似乱数ジェネレーターを作成するために使用するため、毎回同じ値が得られます1。毎回異なるものにしたい場合IOは、コンピューターのラドム状態に基づくジェネレーターを作成する必要があります。計算全体を に入れるよりも、IOに渡す方がきれいStdGenです:
rndPoints3 :: StdGen -> [Point]
rndPoints3 sg = zip x y
where
(sg1, sg2) = split sg
x = randomRs (25, 1000) sg1
y = randomRs (25, 775) sg2
pointsForLabels :: [a] -> StdGen -> [(a, Point)]
pointsForLabels xs sg = zip xs $ rndPoints3 sg
example3 :: [a] -> IO [(a, Point)]
example3 xs = newStdGen >>= return . pointsForLabels xs
ここでnewStdGenは、毎回新しい疑似乱数ジェネレーターを作成しますが、IO. これは最終的にジェネレーターを受け取る純粋な (非IO) 関数に渡され、ランダムなs の無限リストを返します。その関数内で、それから 2 つのジェネレーターを作成するために使用され、それぞれが座標のランダム リストを導出するために使用されます。rndPoints3Pointsplit
pointsForLablesは、ラベルごとに新しいランダム ポイントを照合するロジックを分離するようになりました。また、より役立つ可能性が高いラベルとPoints のペアを返すように変更しました。
最後に、 にexample3住みIO、ジェネレーターを作成し、それ以外の場合は純粋なコードにすべて渡します。