f# - 使用 F# 编译器服务解析计算表达式
问题描述
我开发了一个 F# REST 服务框架,该框架最近已投入生产使用,我正在开发的后续工具之一是自动OpenAPI规范生成器。生成器使用FSharp.Compiler.Services库来检查作为服务入口点公开的每个函数并生成 API 规范,包括每个参数的模式。这些参数通常是单例联合类型,它们使用特殊的rules
计算表达式来定义验证规则,如下所示:
type AccoutNubmerValidationError =
| AccountNumberMustBeTenDigitsLong of string
| AccountNumberMustBeNumerical of string
/// Account Number must be a 10-digit numerical string
[<Struct; Validated>] type AccoutNumber = private AccountNumber of string
module AccountNumber =
let create : string -> Result<AccountNumber, AccountNumberValidationError> =
rules {
rule (Rules.length 10) AccountNumberBeTenDigitsLong
rule (Rules.pattern "^[\d]{10}$") AccountNumberMustBeNumerical
}
我想解析rule
计算表达式中的每一个(这是类CustomOperation
上的a ) ,RulesBuilder
这样我就可以在 OpenApi 架构上为. 虽然我可以识别正确的绑定并且我有主体,但我还没有弄清楚我需要做什么来解析该表达式并提取每个规则的值。 length
pattern
AccountNumber
FSharpExpr
如果有任何关于如何使用 F# Compiler Services 解析计算表达式主体的文档,我还没有找到它。有没有人可以分享任何经验来帮助我解决这个问题?
编辑
我收到了“要求教程”的密切投票,所以我想澄清我的问题。在上面的示例中,我有一个FSharpMemberOrFunctionOrValue
用于create
绑定的实例,以及一个FSharpExpr
用于表达式主体的实例。表达式看起来像这样(表示为 JSON 以使其可读):
{
"Type": "FSharpImplementationFileDeclaration.MemberOrFunctionOrValue",
"Range": {
"StartLine": 15,
"StartCol": 4,
"EndLine": 15,
"EndCol": 9
},
"Properties": [
[
"v",
"val create"
],
[
"vs",
[]
]
],
"Childs": [
{
"Type": "BasicPatterns.Application",
"Range": {
"StartLine": 15,
"StartCol": 4,
"EndLine": 15,
"EndCol": 9
},
"Properties": [],
"Childs": [
{
"Type": "BasicPatterns.Lambda",
"Range": {
"StartLine": 15,
"StartCol": 4,
"EndLine": 15,
"EndCol": 9
},
"Properties": [
[
"lambdaVar",
"val builder@"
]
],
"Childs": [
{
"Type": "BasicPatterns.Call",
"Range": {
"StartLine": 17,
"StartCol": 8,
"EndLine": 17,
"EndCol": 64
},
"Properties": [
[
"memberOrFunc",
"member Require"
],
[
"typeArg2",
"type Microsoft.FSharp.Core.string"
]
],
"Childs": [
{
"Type": "BasicPatterns.Value",
"Range": {
"StartLine": 17,
"StartCol": 8,
"EndLine": 17,
"EndCol": 64
},
"Properties": [
[
"valueToGet",
"val builder@"
]
],
"Childs": []
},
{
"Type": "BasicPatterns.Call",
"Range": {
"StartLine": 16,
"StartCol": 8,
"EndLine": 16,
"EndCol": 63
},
"Properties": [
[
"memberOrFunc",
"member Require"
],
[
"typeArg2",
"type Microsoft.FSharp.Core.string"
]
],
"Childs": [
{
"Type": "BasicPatterns.Value",
"Range": {
"StartLine": 16,
"StartCol": 8,
"EndLine": 16,
"EndCol": 63
},
"Properties": [
[
"valueToGet",
"val builder@"
]
],
"Childs": []
},
{
"Type": "BasicPatterns.Call",
"Range": {
"StartLine": 16,
"StartCol": 8,
"EndLine": 16,
"EndCol": 63
},
"Properties": [
[
"memberOrFunc",
"member Yield"
],
[
"typeArg2",
"type Microsoft.FSharp.Core.obj * Microsoft.FSharp.Core.string"
]
],
"Childs": [
{
"Type": "BasicPatterns.Value",
"Range": {
"StartLine": 16,
"StartCol": 8,
"EndLine": 16,
"EndCol": 63
},
"Properties": [
[
"valueToGet",
"val builder@"
]
],
"Childs": []
},
{
"Type": "BasicPatterns.Const",
"Range": {
"StartLine": 16,
"StartCol": 8,
"EndLine": 16,
"EndCol": 63
},
"Properties": [
[
"constType",
"type Microsoft.FSharp.Core.unit"
],
[
"constValueObj",
null
]
],
"Childs": []
}
]
},
{
"Type": "BasicPatterns.Call",
"Range": {
"StartLine": 16,
"StartCol": 17,
"EndLine": 16,
"EndCol": 32
},
"Properties": [
[
"memberOrFunc",
"val raise"
],
[
"typeArg2",
"type Microsoft.FSharp.Core.obj"
]
],
"Childs": [
{
"Type": "BasicPatterns.Const",
"Range": {
"StartLine": 16,
"StartCol": 17,
"EndLine": 16,
"EndCol": 32
},
"Properties": [
[
"constType",
"type Microsoft.FSharp.Core.int32"
],
[
"constValueObj",
1
]
],
"Childs": []
}
]
},
{
"Type": "BasicPatterns.Const",
"Range": {
"StartLine": 16,
"StartCol": 34,
"EndLine": 16,
"EndCol": 63
},
"Properties": [
[
"constType",
"type Microsoft.FSharp.Core.string"
],
[
"constValueObj",
"Must be 10 digits in length"
]
],
"Childs": []
}
]
},
{
"Type": "BasicPatterns.Call",
"Range": {
"StartLine": 17,
"StartCol": 17,
"EndLine": 17,
"EndCol": 43
},
"Properties": [
[
"memberOrFunc",
"val raise"
],
[
"typeArg2",
"type Microsoft.FSharp.Core.obj"
]
],
"Childs": [
{
"Type": "BasicPatterns.Const",
"Range": {
"StartLine": 17,
"StartCol": 17,
"EndLine": 17,
"EndCol": 43
},
"Properties": [
[
"constType",
"type Microsoft.FSharp.Core.int32"
],
[
"constValueObj",
1
]
],
"Childs": []
}
]
},
{
"Type": "BasicPatterns.Const",
"Range": {
"StartLine": 17,
"StartCol": 45,
"EndLine": 17,
"EndCol": 64
},
"Properties": [
[
"constType",
"type Microsoft.FSharp.Core.string"
],
[
"constValueObj",
"Must be numerical"
]
],
"Childs": []
}
]
}
]
},
{
"Type": "BasicPatterns.Call",
"Range": {
"StartLine": 15,
"StartCol": 4,
"EndLine": 15,
"EndCol": 9
},
"Properties": [
[
"memberOrFunc",
"val rules"
]
],
"Childs": []
}
]
}
]
}
问题是,我什至没有看到对这个表达式树的Rules.length
引用Rules.pattern
。据推测,这一定是因为我正在创建一些中间部分应用的函数,该函数在程序的表达式树的其他地方表示。是否有确定的方法来确定我需要导航的表达式树的哪些部分,然后找到部分应用的函数中使用的实际常量值,以便我可以可靠地以编程方式使用它们?
解决方案
推荐阅读
- autodesk-forge - 伪造查看器中的剪切平面无法使用 ShaderMaterial 剪切对象
- c# - 如何从 C# HttpClient 中的传输编码中获取 UTF8 格式的内容?
- javascript - 在要计数的对象经常变化的模型中计数属性
- php - Symfony 4.1 组件 - 依赖注入问题
- java - Maven 阴影插件无法执行目标?
- checkbox - 复选框单击量角器角度
- python - 将 IP 地址创建为十六进制值
- javascript - 酶`.find(selector)`似乎没有找到选择器
- ag-grid - Ag-Grid 链接与组中单元格中的链接
- html - 仅从我的 angular4 组件渲染 html