5

グラフ ノードを画面に描画するための一連のランダム ポイント (x、y) を取得しようとしています。渡されたノード名ごとにランダムに生成されたポイントが 1 つ必要です。

SOページでこのコードを見つけ、少し修正して動作させましたが、実際には必要なことをしていません。

ランダムな(可能な限りランダムな)(Int、Int)のリストが必要です。

とにかく、ここに私がこれまでに持っているものがあります。もちろん、毎回同じ値を与えるので、特にランダムではありません:)

rndPoints :: [String] -> [Point]
rndPoints [] = []
rndPoints xs = zip x y where
          size = length xs
          x = take size (tail (map fst $ scanl (\(r, gen) _ -> randomR (25::Int,1000::Int) gen) (random (mkStdGen 1)) $ repeat ()))
          y = take size (tail (map fst $ scanl (\(r, gen) _ -> randomR (25::Int,775::Int) gen) (random (mkStdGen 1)) $ repeat ()))

どんな助けでも大歓迎です。

4

2 に答える 2

7

まず、コードを少しクリーンアップしましょう。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、ジェネレーターを作成し、それ以外の場合は純粋なコードにすべて渡します。

于 2013-04-25T06:45:05.673 に答える
0

これにはMonadRandomを使用することになりました。コードが少し明確になり、理解しやすくなったと思います。元の質問に対処するために、次のコードを適応させることができます。

import Control.Applicative
import Control.Monad.Random

type Point = (Float, Float)
type Poly = [Point]

randomScalar :: (RandomGen g) => Rand g Float
randomScalar = getRandomR (-500, 500)

randomPoint :: (RandomGen g) => Rand g Point
randomPoint = (,) <$> randomScalar <*> randomScalar

randomPoly :: (RandomGen g) => Int -> Rand g Poly
randomPoly n = sequence (replicate n randomPoint)
于 2015-03-26T04:04:35.687 に答える