Усреднение списка объектов C # в F #, что не так с моим синтаксисом - PullRequest
1 голос
/ 13 июня 2019

У меня есть список объектов C # с именем Candle (это данные фондового рынка), и мне нужно усреднить несколько из этих объектов в один.

Объекты очень простые, они просто содержат поля с плавающей точкой (Bid, Ask, Bidvolume, Askvolume)

Я написал этот код, но я не понимаю, почему он не компилируется:

            let zero = new Candle()
            let avg =   entries
                        |> List.fold (fun acc elem ->
                                (
                                    Ask = acc.Ask + elem.Ask,
                                    Bid = acc.Bid + elem.Bid,
                                    AskVolume = acc.AskVolume + elem.AskVolume,
                                    BidVolume = acc.BidVolume + elem.BidVolume
                                )
                            ) zero
                        |>
                            (
                                TimeStamp = time,
                                Ask = Ask / entries.Count,
                                Bid = Bid / entries.Count,
                                AskVolume = AskVolume / entries.Count,
                                BidVolume = BidVolume / entries.count,
                                Integrity = entries.Count / expectedCount
                            )

Я получаю следующие ошибки:

  BooksCandle.fs(154, 41): [FS0039] The value or constructor 'Ask' is not defined.
  BooksCandle.fs(154, 51): [FS0039] The field, constructor or member 'Ask' is not defined.
  BooksCandle.fs(155, 41): [FS0039] The value or constructor 'Bid' is not defined. Maybe you want one of the following:   id
  BooksCandle.fs(155, 51): [FS0039] The field, constructor or member 'Bid' is not defined.
  BooksCandle.fs(156, 41): [FS0039] The value or constructor 'AskVolume' is not defined.
  BooksCandle.fs(156, 57): [FS0039] The field, constructor or member 'AskVolume' is not defined.
  BooksCandle.fs(157, 41): [FS0039] The value or constructor 'BidVolume' is not defined.
  BooksCandle.fs(157, 57): [FS0039] The field, constructor or member 'BidVolume' is not defined.
  BooksCandle.fs(159, 35): [FS0001] This expression was expected to have type    'bool * bool * bool * bool'    but here has type    'Candle'
  BooksCandle.fs(162, 37): [FS0001] This expression was expected to have type    'bool * bool * bool * bool -> 'a'    but here has type    ''b * 'c * 'd * 'e * 'f * 'g'
  BooksCandle.fs(170, 22): [FS0039] The value or constructor 'A' is not defined.

Итак, я предполагаю, что объект, которым я манипулирую, не рассматривается как Candle, но использование fun (acc : Candle) (elem : Candle) совсем не помогает.

Ответы [ 3 ]

3 голосов
/ 13 июня 2019

Вы используете () разделители для того, что кажется записью, но записи используют {} разделители.Измените свою первую трубу на эту:

(fun acc elem ->
            {
                Ask = acc.Ask + elem.Ask,
                Bid = acc.Bid + elem.Bid,
                AskVolume = acc.AskVolume + elem.AskVolume,
                BidVolume = acc.BidVolume + elem.BidVolume
            }
)

Затем также измените вторую трубу, как предложено в ответе Честера Хаска.

РЕДАКТИРОВАТЬ: Нет, подождите.Тот факт, что у вас есть линия let zero = new Candle(), заставляет меня переосмыслить это.И вы сказали ранее, что Candle является объектом C #.Тогда в этом случае вы фактически пытаетесь изменить поля только что созданного объекта zero.В этом случае вам нужен оператор <-.F # сознательно проводит различие между операторами = и <-.Оператор = означает равенство и также используется в let x = 5, поскольку значение x не может измениться и всегда будет равно 5 в остальной части этого кодаблок, поскольку x не был отмечен mutable.(Если x является объектом, объект может видоизменить свои внутренние объекты, но имя x всегда будет ссылаться на этот объект).Оператор <-, с другой стороны, используется для назначения.Он выглядит отличным от оператора =, потому что вы не обещаете, что это значение останется там навсегда.

Итак, сказав, что вам действительно нужно поменять аккумуляторФункция выглядит примерно так:

(fun acc elem ->
    acc.Ask <- acc.Ask + elem.Ask,
    acc.Bid <- acc.Bid + elem.Bid,
    acc.AskVolume <- acc.AskVolume + elem.AskVolume,
    acc.BidVolume <- acc.BidVolume + elem.BidVolume
    acc
)

Обратите внимание, как я возвращаю acc, записав его отдельно в последнюю строку.Последнее выражение в функции F # является его возвращаемым значением;ключевое слово return не требуется.

Тогда ваш второй канал должен передать в функцию:

|> (fun result ->
        result.TimeStamp <- time,
        result.Ask <- result.Ask / float entries.Count,
        result.Bid <- result.Bid / float entries.Count,
        result.AskVolume <- result.AskVolume / float entries.Count,
        result.BidVolume <- result.BidVolume / float entries.count,
        result.Integrity <- entries.Count / expectedCount
)

Обратите внимание, как я преобразовал entries.Count в float, потому что я предполагаю, что ваш Ask и Bid значения являются числами с плавающей запятой.Если они являются целыми числами, удалите это преобразование float, но имейте в виду, что F # использует деление integer при делении целых чисел, например, значение 5 / 2 будет равно 2, а не 2,5.Если вы хотите 2,5, вам придется делить поплавки, 5.0 / 2.0.

2 голосов
/ 13 июня 2019

В F # объекты и записи - это разные вещи. Вы можете создать значение записи следующим образом:

{ Foo = "apple"; Bar = "banana" }

Но вы не можете использовать подобный синтаксис для создания объекта. Код ниже не компилируется:

( Foo = "apple", Bar = "banana" )

Потому что это будет пониматься как:

  • кортеж из 2 компонентов, потому что он имеет вид ( component1, component2 ).
  • каждый компонент является значением bool, потому что есть сравнение =.
  • Foo ожидается как значение имени Foo, но здесь такого понятия не существует. Аналогично для Bar.

Вместо этого вы должны написать: new MyClass ( Foo = "apple", Bar = "banana" )

Я хотел бы переписать ваш код, как показано ниже:

let zero = new Candle ()
let sum =
    entries
    |> List.fold
        (fun acc elem ->
            new Candle (
                Ask = acc.Ask + elem.Ask,
                Bid = acc.Bid + elem.Bid,
                AskVolume = acc.AskVolume + elem.AskVolume,
                BidVolume = acc.BidVolume + elem.BidVolume
            )
        )
        zero
let avg = new Candle (
    TimeStamp = time,
    Ask = sum.Ask / float entries.Length,
    Bid = sum.Bid / float entries.Length,
    AskVolume = sum.AskVolume / float entries.Length,
    BidVolume = sum.BidVolume / float entries.Length,
    Integrity = float entries.Length / float expectedCount
)

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

2 голосов
/ 13 июня 2019

Принимая удар здесь, но я собираюсь догадаться, что линия 154 в трубе после вашего сгиба?Если да, то проблема в синтаксисе: вместо

|> (.... 

вам нужно передать результат сгиба в функцию:

|> fun reduced -> { TimeStamp = time
                    Ask = reduced.Ask/entries.Count
                    .... }

используя свойства восстановленного элемента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...