我将自己设置为创建一个行为类似于sprintf
or的跟踪函数printfn
,但使用ConditionalAttribute
.
到目前为止的结果:我认为这是不可能的。
问题集中在这样一个事实,即当您使用Conditional("DEBUG")
属性时,函数必须返回单位结果。“正常”参数按应有的方式工作,并且该方法已正确修饰(编辑:修饰,是的,但可咖喱成员没有被删除,请参阅讨论,必须改用元组形式):
type Trace() =
[<Conditional("DEBUG")>]
static member inline trace msg b = (msg, b) |> ignore
// using it, x is unit
let x = Trace.trace "test" "foo"
(请注意,没有ignore
,由于 Conditional 属性,这将无法编译)
但是,一旦我尝试了 的任何变体Printf.TextWriterFormat<'T>
,它就会失败,而且我看不到解决方法:
type Trace() =
[<Conditional("DEBUG")>]
static member inline trace msg = printfn msg // inline or not doesn't matter
// using it, x is unit
let x = Trace.trace "hello: %s" "foobar"
这在没有属性的情况下有效,但使用属性,它将引发:
这个表达式应该有类型
unit
,但这里有类型
string -> unit
该错误特别强调Trace.trace "hello: %s"
。所以看起来编译器没有识别出整个表达式导致 a unit
,并引发错误,因为它在内部创建了一个返回的包装函数string -> unit
,这是ConditionalAttribute
.
当我尝试通过显式指定:unit
函数返回类型或printfn msg |> ignore
作为主体来修复它时,我失去了使用类型安全的文本编写器格式字符串的能力,事实上,它不会识别调用中的第二个参数- 网站不再。
因此,虽然整个函数签名都遵循 CLR 的规则,但 F# 创建的内联函数似乎没有,至少在这种特定情况下没有。
我尝试过变体,包括kprintf
,sprintf
看看是否有帮助,但都无济于事。
有任何想法吗?或者这是您尝试铺设地毯的情况之一,一旦您将它在一个角落正确平滑,它会在另一个角落冒泡,反之亦然,即它永远不适合?
PS:如果您想知道我为什么想要它:只是尝试创建一个行为类似于现有 Trace 的便利函数,但在后台运行一些其他功能。我目前拥有的作品,但它只需要一个字符串,而不是静态类型检查的参数,所以它迫使用户编写如下内容:
(sprintf "Hello %s" >> Trace.trace) "foobar"