Используя Scala, существует ли функциональная парадигма для анализа живых данных?

Например, при анализе данных о реальном фондовом рынке я предоставляю метод своим клиентам

def onTrade(trade: Trade) {
}

Клиенты могут делать что угодно: от подсчета количества сделок, вычисления средних значений, хранения высоких минимумов, сравнения цен и т.д. Метод, который я выставляю, ничего не возвращает, и клиенты часто используют vars и изменяемые структуры для их вычисления. Например, при вычислении общих сделок они могут делать что-то вроде

var numTrades = 0

def onTrade(trade: Trade) {
    numTrades += 1
}

Один вызов onTrade может потребовать шесть или семь разных вещей. Есть ли способ примирить этот тип гибкости с функциональной парадигмой? Другими словами, тип возврата, vals и не подлежащие обработке структуры данных

Ответ 1

Возможно, вы захотите изучить Функциональное реактивное программирование. Используя FRP, вы будете выражать свои сделки как поток событий и управлять этим потоком в целом, вместо того, чтобы сосредоточиться на одной сделке за раз.

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

В приведенной выше ссылке содержатся ссылки на несколько реализаций Haskell, но, возможно, существует также несколько реализаций FRW Scala.

Ответ 2

Одна возможность заключается в использовании monads для инкапсуляции состояния в рамках чисто функциональной программы. Вы можете проверить библиотеку Scalaz.

Кроме того, согласно отчетам, команда Scala разрабатывает подключаемый модуль компилятора для системы эффектов. Тогда вы можете подумать о предоставлении такого интерфейса для своих клиентов,

def callbackOnTrade[A, B](f: (A, Trade) => B)

Клиенты определяют свои типы ввода и вывода A и B и определяют чистую функцию f, которая обрабатывает сделку. Все "состояние" инкапсулируется в A и B и пронумеровано через f.

Ответ 3

Обратные вызовы могут быть не лучшим подходом, но есть определенные функциональные схемы, которые могут решить такую ​​проблему. Возможно, вы захотите рассмотреть FRP или решение state-monad, как уже было предложено, и другие возможности - это другая форма потока данных concurrency, и вы также можете воспользоваться методом copy, который автоматически генерируется для классов case.

Другой подход - использовать STM (программную транзакционную память) и придерживаться императивной парадигмы, сохраняя при этом некоторую безопасность.

Лучший подход зависит от того, как вы сохраняете данные и что вы на самом деле делаете в этих изменениях состояния. Как всегда, пусть профилировщик будет вашим руководством, если производительность будет критической.