F #: как оценить последовательность, чтобы получить все ее значения?

Мы знаем, что в F# seq вычисляется лениво. Мой вопрос: если у меня есть последовательность с ограниченным количеством значений, как преобразовать ее в некоторый тип данных, который содержит все его оцениваемые значения?

> seq { for i in 1 .. 10 do yield i * i };;
val it : seq<int> = seq [1; 4; 9; 16; ...]

Большое спасибо.


person vik santata    schedule 03.02.2016    source источник


Ответы (2)


Ответ от @Carsten правильный: вы можете использовать Seq.toArray или Seq.toList, если хотите преобразовать лениво оцениваемые последовательности в списки или массивы. Однако не используйте эти функции для принудительной оценки.

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

let lazySeq = seq { for i in 1 .. 10 do yield i * i }
let nothingHappens = lazySeq |> Seq.map (printfn "%i")

Проблема в том, что при оценке этих двух выражений ничего не происходит:

> 

val lazySeq : seq<int>
val nothingHappens : seq<unit>

Поскольку nothingHappens является ленивой вычисляемой последовательностью, никаких побочных эффектов от map не возникает.

Люди часто прибегают к Seq.toList или Seq.toArray для принудительной оценки:

> nothingHappens |> Seq.toList;;
1
4
9
16
25
36
49
64
81
100
val it : unit list =
  [null; null; null; null; null; null; null; null; null; null]

Хотя это работает, это не особенно идиоматично; он возвращает странный тип: unit list.

Более идиоматичным решением является использование Seq.iter:

> lazySeq |> Seq.iter (printfn "%i");;
1
4
9
16
25
36
49
64
81
100
val it : unit = ()

Как вы можете видеть, это вызывает принудительную оценку, но имеет более разумный тип возвращаемого значения unit.

person Mark Seemann    schedule 03.02.2016
comment
В моей ситуации последовательность строится из ресурсов, которые необходимо утилизировать после построения. Я не вижу другого способа обойти это, кроме как вызвать toList, затем toSeq, затем удалить ресурс и вернуть результирующую последовательность. В этом случае оценка должна быть принудительной, даже если нет никаких побочных эффектов. - person Kurren; 31.05.2017
comment
@Kurren Ваш пример полезен. Спасибо! Однако технически в вашем примере есть есть побочные эффекты. Побочные эффекты происходят в одноразовых ресурсах. - person Wallace Kelly; 12.12.2019
comment
Это, наконец, решило мою аналогичную проблему... и, конечно же, у Плоэ был полезный ответ и четкое объяснение. Спасибо за все, что вы делаете. - person Kurt Mueller; 14.05.2021

используйте Seq.toArray (для массива) или Seq.toList (для списка);)

есть еще много всего - выбирай ;)


пример:

> seq { for i in 1 .. 10 do yield i * i } |> Seq.toArray;;
val it : int [] = [|1; 4; 9; 16; 25; 36; 49; 64; 81; 100|]
person Random Dev    schedule 03.02.2016