在我重新发明轮子之前:有人知道已经为 LP 提供了 DSL 的好的库吗?
不,除了Microsoft SolverFoundation本身的 ODSL ,我什么都不知道。
否则,您将如何在 F# 中构建这样的 DSL?
决定语言的语法。尽管您想构建内部 DSL,但您必须决定什么是允许的,什么是您的语言无法表达的。
使用F# 引用来获取 AST。为什么需要反思?首先,您创建一堆变量并将它们与浮点常量组合以形成线性约束。稍后,您将使用适当的值填充这些变量。反射允许您创建占位符并稍后计算结果。
在 CLP 中将 AST 转换为线性程序并求解。似乎 CLP 没有 .NET API;您可以通过命令行与求解器进行通信,但它不是很方便和健壮。在创建 DSL 之前开始构建低级 API 是个好主意。
(可选)在 F# 3.0 中,您可以为您的 DSL 创建查询语法。你可以看看一个令人信服的例子,内置查询表达式。
由于 Microsoft Solver Foundation 已被弃用,我正在尝试寻找一种替代或合理的方式来创建我自己的 DSL。
无论如何,无国界医生将为您的工作提供有价值的例子。您可以在此代码库中浏览 ODSL 源代码。实际上,从代码库中您可以看到 ODSL 已经完成了三个第一步。我正在 ODSL 之上构建优化查询语言(步骤 4),并且只完成了表面语法。例如,这个原始示例
<@
let sa = var<Barrel/Day>()
let vz = var<Barrel/Day>()
minimise (20.0<Dollar/Barrel> * sa + 15.0<Dollar/Barrel> * vz)
where
[
0.3 * sa + 0.4 * vz >= 2000.<Barrel/Day>;
0.4 * sa + 0.2 * vz >= 1500.<Barrel/Day>;
0.2 * sa + 0.3 * vz >= 500.<Barrel/Day>;
sa <= 9000.<Barrel/Day>;
vz <= 6000.<Barrel/Day>;
sa >= 0.<Barrel/Day>;
vz >= 0.<Barrel/Day>
]
@>
将转变为
opt { let! sa = var<Barrel/Day>()
let! vz = var<_>()
assume (0.3 * sa + 0.4 * vz >= 2000.<_>)
assume (0.4 * sa + 0.2 * vz >= 1500.<_>)
assume (0.2 * sa + 0.3 * vz >= 500.<_>)
assume (sa <= 9000.<_> && sa >= 0.<_>)
assume (vz <= 6000.<_> && vz >= 0.<_>)
minimise (20.0<Dollar/Barrel> * sa + 15.0<_> * vz)
}
如果您有兴趣,我还在这里翻译了一些 DSL 示例。