2016-11-20 11 views
1

Как вы используете значения IO Double, полученные из генератора глобальных случайных чисел в Haskell в арифметических и логических операциях? Большинство учебных пособий в Интернете сосредоточены на получении случайных чисел, но почему-то я, похоже, не могу что-то сделать с ними.Использование случайных значений, полученных от генератора глобальных случайных чисел в Haskell в арифметических и логических операциях

Следующий код содержит некоторую функцию test, содержащую некоторые из операций, которые я хочу выполнить.

{-# LANGUAGE Strict #-} 
module RNG where 
import System.Random(setStdGen, mkStdGen, randomRIO) 

seed_rng :: Int -> IO() 
seed_rng seed = (setStdGen (mkStdGen seed)) 

uniform_float :: IO Double 
uniform_float = (randomRIO (0.0, 1.0)) 

test :: Double -> Double -> IO Double 
test a b = let u = (uniform_float) 
       in if ((<) (return a) u) then ((+) (return b) u) else (return 2.0) 

Тест функция не компилируется, так как нет ни одного случая для Ord (IO Double) и Num (IO Double).

Обратите внимание, что я могу избежать IO Monad путем внедрения генератора случайных чисел и отслеживания и передачи состояния. Но я предпочитаю учиться работать с Monads вместо того, чтобы всегда пытаться убежать от них.

+0

Тангенциального вопрос: есть ли какие-либо конкретные причины, почему вы используете '{- # LANGUAGE Строгий # -} '? – duplode

+1

@duplode Очень эффективный критический код (практически только дробление числа). Мне на самом деле никогда не нужны плюсы ленивой оценки. – Matthias

+0

Хорошо, это звучит разумно. – duplode

ответ

4

В монадическом контексти, вы можете использовать do на самом деле запустить вычисление:

test :: Double -> Double -> IO Double 
test a b = do 
    u <- uniform_float 
    if a < u 
     then return (b + u) 
     else return 2.0 

Основной идея: использовать <- временно извлечь Double из IO Double, а затем поместить результат обратно в IO используя return.

Например, это суммирует два равномерного число:

sumTwo :: IO Double 
sumTwo = do 
    x <- uniform_float 
    y <- uniform_float 
    return (x+y) 

Есть альтернативы do, но я бы рекомендовал обучение do первым, так как это достаточно разумно общие и простые. Когда вы привыкнете к монадическим вычислениям, аппликациям и функторам, вам, вероятно, также понравятся компактные альтернативы, такие как sumTwo = (+) <$> uniform_float <*> uniform_float.

+0

Большое спасибо, как шарм! – Matthias

3

(>>=) можно использовать для привязки второго монадического вычисления, которое использует значения Double.

test :: Double -> Double -> IO Double 
test a b = uniform_float >>= \u -> return (if a < u then b + u else 2.0) 

Альтернативный способ написания выше используют Do-блок:

test :: Double -> Double -> IO Double 
test a b = do 
    u <- uniform_float 
    return (if a < u then b + u else 2.0) 

Наконец, в тех случаях, как этот, в котором второй монадической вычисление является просто без монадической вычисления с последующей по return, вам не нужно даже (>>=) - fmap достаточно:

test :: Double -> Double -> IO Double 
test a b = fmap (\u -> if a < u then b + u else 2.0) uniform_float