Testing F#是否具有访问词法作用域的语言构造(如python locals()/globals())
在F#中编写测试时,我试图生成有关导致错误的状态的有用消息。在python中,我将包含所有的locals(),因此它们在测试跟踪中很容易访问 F#中是否有类似的构造 我一直在搜索网络和优秀的fsharpforfunandprofit网站,并浏览了保留关键字列表 下面是一些我希望能够做到的代码Testing F#是否具有访问词法作用域的语言构造(如python locals()/globals()),testing,f#,metaprogramming,language-features,fscheck,Testing,F#,Metaprogramming,Language Features,Fscheck,在F#中编写测试时,我试图生成有关导致错误的状态的有用消息。在python中,我将包含所有的locals(),因此它们在测试跟踪中很容易访问 F#中是否有类似的构造 我一直在搜索网络和优秀的fsharpforfunandprofit网站,并浏览了保留关键字列表 下面是一些我希望能够做到的代码 [] 让我们来测试x= 让我们举一个例子= 设z=y+x //我正在寻找的元构造示例 设作用域={| 局部={y=y;z=z}; 俘获={| 局部={x=x}; 捕获={|(*…*)|}; |}; |} x
[]
让我们来测试x=
让我们举一个例子=
设z=y+x
//我正在寻找的元构造示例
设作用域={|
局部={y=y;z=z};
俘获={|
局部={x=x};
捕获={|(*…*)|};
|};
|}
x=z |@sprintf“需要%A=%A(%A)”x y范围
示例\u内部\u辅助对象(x+x)
这将产生非常有用的输出
Tests.some_test
Source: Tests.fs line 105
Duration: 51 ms
Message:
FsCheck.Xunit.PropertyFailedException :
Falsifiable, after 1 test (1 shrink) (StdGen (387696160,296644521)):
Label of failing property: require 1=2 ({ capture = { capture = {}
local = { x = 1 } }
local = { y = 2
z = 3 } })
Original:
-1
Shrunk:
1
但是,我必须显式地捕获像“scope”这样的构造可以自动提供的信息。导致了丑陋的、容易出错的东西,比如
让``FirstUpsingLastDownsingParte Prop```(a:区段)b=
让我们来验证ea-eb=
让我们检查Xbeforey ex ey headx restx=
将restx与
|ValueNone->//无剩余
(ex=headx)|@sprintf“无休息:ex=headx(%A=%A)”ex-headx
.&. ((相交ex-ey)=ValueNone)|@sprintf“无剩余:ex∩ ey=∅ (%A)∩ %A) “是的
|ValueSome rex->//Some rest->
//headx和restx合并到ex
((expandE-headx-rex)=ex)|@sprintf“rest:headx+rex=ex(%A..%A)”headx-rex
.&. (exactlyTouchesE headx rex)|@sprintf“rest:headx在rex开始的地方结束(ex=%A ey=%A headx=%A restx=%A)”ex ey headx restx
.&. (exactlyTouchesE headx ey)|@sprintf“rest:headx在ey开始的地方结束(ex=%A ey=%A headx=%A restx=%A)”ex ey headx restx
....
(当然,我不关心“范围”构造的实际类型)
关于取消报价
我已经看过unquote了,它很可爱,看起来不错。但它在很大程度上限制了代码:
- 错误FS3155引用可能不涉及分配或获取捕获的局部变量的地址
- 错误FS1230引用表达式中不允许使用内部泛型函数。考虑添加一些类型约束,直到该函数不再是泛型。
[]
类型X)=X.第一次试验
|>试验
第一种方法是使用函数访问结构部件,但泛型的限制是PITA。我认为没有办法做到这一点,即使在原则上也是如此。F#代码被编译成基于堆栈的.NET字节码,因此编译后的代码中实际上(通常)不存在局部变量。您可能能够获取一些全局变量(它们是静态成员),或者以某种方式使用调试信息,但我认为没有一种标准的方法可以做到这一点 也就是说,在您的具体案例中,F#实际上有一个很好的选择,即使用测试框架。这使您可以将测试代码放入F#引号中,然后显示该引号的计算方式。例如:
let some_test x =
let example_inner_helper y =
<@
let z = y + x
x = z
@> |> test
example_inner_helper (x+x)
some_test 10
谢谢你。我实际上是从unquote开始的,但对可以引用的表达式的限制有问题(se更新到问题)。
Test failed:
let z = y + x in x = z
let z = 20 + 10 in x = z
let z = 30 in x = z
false