Использование F# для создания хорошо отлаживаемого движка бизнес-правил
Эта проблема
У меня есть код в F#, представляющий логическое дерево. Это механизм бизнес-правил с некоторыми довольно простыми математическими функциями. Я хотел бы иметь возможность запускать правила дерева много раз и видеть, сколько раз проходит каждый конкретный маршрут через дерево.
Требования состоят в том, чтобы базовые правила не менялись слишком сильно по сравнению с простыми операторами соответствия, которые я использую в данный момент. Было бы хорошо пометить важные функции атрибутом, но добавить вызов функции регистрации в каждом узле - нет. Я хочу иметь возможность запускать код в двух режимах: высокопроизводительный стандартный режим, который просто дает ответы, а затем "исследовательский режим", который дает больше деталей за каждым вызовом. Хотя я не против сложного кода для динамической загрузки и профилирования правил, сам код правил должен выглядеть просто. В идеале я не хотел бы полагаться на сторонние библиотеки - powerpack в порядке. Решение также должно быть нацелено на среду выполнения.NET 4.0.
Потенциальные решения
Добавьте вызов регистрации для каждой функции с именем функции и аргументами. Мне это не нравится, потому что даже если бы я мог отключить его в каком-то режиме релиза, он все еще загромождает правила и означает, что весь новый код должен быть написан неестественным образом.
Каждая функция возвращает свой результат, а затем список, который содержит имена методов, которые до сих пор вызывались. Мне это не нравится, потому что это выглядело бы неестественно и было бы ударом по производительности. Я уверен, что мог бы использовать вычислительное выражение, чтобы выполнить большую часть сантехники, но это нарушает требование сохранять правила простыми.
Проанализируйте дерево правил с помощью цитат, а затем создайте новое выражение, которое является старым выражением, с вызовом функции ведения журнала, внедренной в сайт каждой теговой функции. Это лучшее, что у меня есть, но я беспокоюсь о том, чтобы составить полученную цитату, чтобы я мог ее запустить. Я понимаю (пожалуйста, поправьте меня, если я ошибаюсь), что не все цитаты могут быть скомпилированы. Я бы предпочел не иметь нестабильного процесса, который ограничивает код правил подмножеством языка F#. Если правила скомпилируются, я бы хотел, чтобы мое решение имело дело с ними.
Я знаю, что это сложная проблема с довольно строгим набором требований, но если у кого-то есть вдохновение для решения, я был бы очень благодарен.
Редактировать: просто, чтобы привести пример правил, которые я мог бы использовать, если бы я владел фабрикой виджетов, производящей продукты A и B, мог бы использоваться простой следующий код. Я не хочу потерять удобочитаемость и простоту формул, украсив этот слой вспомогательными функциями и хуками.
type ProductType = | ProductA | ProductB
let costOfA quantity =
100.0 * quantity
let costOfB quantity =
if quantity < 100.0 then
20.0 * quantity
else
15.0 * quantity
let calculateCostOfProduct productType quantity =
match productType with
| ProductA -> costOfA quantity
| ProductB -> costOfB quantity