Проекция F# RX [закрыта]

Хотите преобразовать код C# для RX в код F#. Следующий код C# работает хорошо:

  var seqNum = Observable.Range(1, 5);
  var seqString = from n in seqNum
                  select new string('*', (int)n);
  seqString.Subscribe(str => { Console.WriteLine(str); });
  Console.ReadKey();

Ниже приведен мой код на F#:

#light
open System
open System.Collections.Generic
open System.Linq
open System.Reactive
open System.Reactive.Linq
open System.Reactive.Subjects
open System.Threading
open System.IO

let seqNum = Observable.Range(1, 5)
let seqString = from n in seqNum
                select new string('*', (int)n)
Console.ReadLine() |> ignore

Но я получил следующую ошибку компилятора: Ошибка: неожиданное ключевое слово «новое» в файле реализации

Если я удалил новое ключевое слово, я получил еще одну ошибку: Ошибка: последовательные аргументы должны быть разделены пробелами или объединены в кортеж, а аргументы, включающие приложения функций или методов, должны быть заключены в круглые скобки.

Ключевое слово «новое» совершенно отличается в C# и F#. Пожалуйста, покажите мне, как сделать ту же работу в F #. Спасибо,


person John John    schedule 08.01.2012    source источник


Ответы (3)


Ну вот:

open System
open System.IO
open System.Reactive
open System.Reactive.Linq

let seqString = Observable.Range(1,5).Select(fun x -> String.replicate x "*")
using (seqString.Subscribe (fun x -> printfn "%s" x))
    (fun _ -> Console.ReadLine() ) |> ignore

EDIT: как Пол предложил ниже, две последние строки можно заменить простыми

seqString.Subscribe (printfn "%s") |> ignore

Однако, если мы хотим изящно отказаться от подписки, но избавиться от using вместо более нового синтаксиса use, мы можем заменить последние две строки следующими тремя

do
    use subscription = seqString.Subscribe(printfn "%s")
    Console.ReadLine() |> ignore
person Gene Belitski    schedule 08.01.2012
comment
Вам не нужно (и, по сути, не следует) выбрасывать подписку здесь - person Ana Betts; 09.01.2012
comment
@PaulBetts: (a) Console.ReadLine() в блоке using гарантирует, что удаление произойдет только **после ** нажатия Enter на клавиатуре, как предполагает исходный код C#; и (b) что более важно, Observable.Range(1,5) эквивалентно Observable.Range(1,5,Scheduler.CurrentThread), что делает код эффективным однопоточным, поэтому избавление от подписки здесь абсолютно безопасно, почему бы и нет? - person Gene Belitski; 09.01.2012
comment
Привет, Джин Белицки: Большое спасибо, ваш код работает. Однако мне трудно понять, когда использовать использование, а когда использовать использование, я думаю, что только C # использует использование, а не F #! - person John John; 09.01.2012
comment
Поскольку семантика IObservable.Subscribe заключается в том, что вы можете использовать Dispose только в том случае, если хотите досрочно прекратить подписку. В этом случае вы не хотите удалять его раньше, и единственный способ избежать неприятностей — это планировать источник в контексте. - person Ana Betts; 09.01.2012
comment
@JohnJohn: вы можете посмотреть здесь объяснения различий между use и using. Но вы также можете смело придерживаться use, который представляет собой синтаксическую сахарную форму привязки, которая обеспечивает автоматический вызов Dispose(), когда значение IDisposable выходит за рамки. - person Gene Belitski; 10.01.2012

В C# string — это ярлык для класса System.String. Однако в F# string — это функция, которая имеет на входе obj и возвращает строку, которая переопределяется в obj.ToString():

let s = string('*', 3);; // tuple to string
// val s : string = "(*, 3)"

Что вам действительно нужно, так это создать строку, повторив '*' три раза:

let s = new String('*', 3)
// val a : String = "***"

Чтобы было ясно, from ... in ... select ... — это синтаксис C# LINQ, который недопустим в F#. Поэтому, используя вместо этого вычислительное выражение:

let seqNum = seq {1..5}
let seqString = seq { for n in seqNum -> new String('*', n) }

Чтобы получить некоторые идеи о создании/использовании вычислительного выражения для Reactive Extension, взгляните на вопрос и его ответы на Как мне изменить реализацию Rx Builder, чтобы исправить исключение переполнения стека?

person pad    schedule 08.01.2012
comment
Привет, Пад: Спасибо, твой код работает. Однако из исходного кода C# я не знаю, как подписаться на Observable. Пожалуйста, покажите мне, как я могу подписаться на него. - person John John; 09.01.2012
comment
@John: ты был слишком быстр, чтобы принять ответ блокнота. См. ниже мой рабочий порт F# вашего оригинального фрагмента C#. Хотя вы не можете использовать LINQ в F# C#, тем не менее, вы можете использовать его через точечную запись. - person Gene Belitski; 09.01.2012
comment
Что-то вроде seqString.Subscribe(fun s -> Console.WriteLine(s)) будет работать. - person pad; 09.01.2012

Вместо конструктора String используйте метод String.replicate.

String.replicate n "*"

Прямого эквивалента для String(char, int) нет, но String.replicate: int -> string -> string примерно соответствует string вместо char.

Версия F# для этого кода

[1 .. 5]
|> Seq.map (fun i -> String.replicate i "*")
person JaredPar    schedule 08.01.2012
comment
Привет: JaredPar: я изменил свой код на: let seqString = from n in seqNum select (String.replicate n *) Но я получил еще более ужасную ошибку компилятора: Ошибка: значение или конструктор 'from' не определен Компилятор F # сделал НЕ даже распознавать ключевое слово для LINQ. Скажи мне что делать. Спасибо! - person John John; 09.01.2012
comment
@JohnJohn Я думал, что вы используете предварительную версию, в которую они добавили LINQ (почти уверен, что она там добавлена). Версия RTM не поддерживает LINQ. Я добавлю эквивалентную версию F# для этого конкретного кода. - person JaredPar; 09.01.2012
comment
Привет, JaredPar: я изменил свой код, чтобы он выглядел следующим образом: let xx = [1 .. 5] |› Seq.map (fun i -> String.replicate i *) |› (fun x -> x.ToObservable( )) |› (fun y -> y.Subscribe(printfn %s)) - person John John; 09.01.2012
comment
Привет, JaredPar: ваш код лучше, но он не делал того, что делал исходный код: подписывался на наблюдаемое. Я добавил код, который выполняет эту работу, дайте мне знать, что вы думаете! Спасибо за вашу помощь! - person John John; 09.01.2012
comment
@JohnJohn Я менее знаком с Observable, но ваш код мне кажется правильным. - person JaredPar; 09.01.2012