Последовательность, построенная из предыдущего элемента Последовательности и другой Последовательности - PullRequest
1 голос
/ 11 апреля 2011

В целях обучения я пытаюсь запустить симуляцию в виде последовательности с F #. Начиная с последовательности случайных чисел, map - это простой способ генерации последовательности состояний, если состояния не зависят от предыдущих состояний. Я сталкиваюсь с проблемой, когда пытаюсь сделать что-то вроде:
State (i + 1) = F (State (i), случайное число)
Мне удалось заставить что-то работать, используя раскрытие, передавая генератор случайных чисел по линиям

  let unfold (day:State,rnd:Random) =
    let rand = rnd.NextDouble()
    let nextDay = NextState day rand
    Some (nextDay, (nextDay, rnd))

Однако, по крайней мере, на мой неопытный взгляд, что-то в прохождении случайного экземпляра кажется подозрительным. Есть ли способ добиться чего-то подобного, но передать последовательность случайных чисел, а не генератор?

Ответы [ 3 ]

4 голосов
/ 11 апреля 2011

Я бы согласился с BrokenGlass, что использование глобального экземпляра Random в этом случае выглядит нормально.Это разумно локализованное использование изменяемого состояния, поэтому оно не должно вводить в заблуждение.

В качестве альтернативы unfold, вы можете явно записать вычисление:

let simulationStates = 
    let rnd = new Random()
    let rec generate (day:State) = seq {
        let rand = rnd.NextDouble()
        let nextDay = NextState day rand 
        yield nextDay
        yield! generate nextDay }
    generate InitialState

Примечаниечто значение rnd является локальной переменной с областью, ограниченной только определением simulationStates.Это довольно хороший способ отделить изменяемое состояние от остальной части программы.

Версия, использующая unfold, вероятно, более лаконична;этот может быть легче для чтения, так что это зависит от ваших личных предпочтений стиля.

3 голосов
/ 11 апреля 2011

Я думаю, что ваша догадка о том, чтобы передать экземпляр Random как подозрительный, справедлива: когда изменяемое состояние полезно, полезно изолировать его, чтобы вы как можно больше выиграли от чистоты.

Здесь мы можем выделить состояние, создав последовательность, которая выдает различный набор случайных чисел на каждой итерации

open System
let rndSeq = 
    seq {
        //note that by putting rnd inside seq expression here, we ensure that each iteration of the sequence
        //yields a different sequnce of random numbers
        let rnd = new Random()
        while true do yield rnd.NextDouble()
    }

затем вы можете использовать Seq.scan для итерации случайной последовательности путем сопоставления элементов с использованием функции, которая сообщается предыдущим отображенным элементом.

let runSimulation inputSeq initialState =
    inputSeq
    |> Seq.scan 
        (fun (previousState:State) (inputElement:float) -> NextState previousState inputElement) 
        initialState

runSimulation rndSeq initialState //run the simulation using a random sequence of doubles greater than or equal to 0.0 and less than 1

Здесь вы можете видеть в качестве дополнительного бонуса, что ваша симуляция ввода и реализация симуляции больше не связаны, вы можете запустить симуляцию, используя любую последовательность ввода.

2 голосов
/ 11 апреля 2011

Может быть против духа, но я бы просто использовал глобальный случайный экземпляр в этом случае - в качестве альтернативы вы могли бы определить последовательность случайных чисел, как это:

...