0

我将自己设置为创建一个行为类似于sprintfor的跟踪函数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"
4

1 回答 1

3

基于重载的版本。

你可能想要更多的重载

#if DEBUG
type Log() =
    static member inline log(x) = printfn x
    static member inline log(x,y) = printfn x y
#else
type Log =
    static member inline log(x) = ()
    static member inline log(x,y) = ()
#end

更新:

所以这有效:

open System.Diagnostics
type Log() =
    [<Conditional("DEBUG")>]  
    static member log(x) = printfn x
    [<Conditional("DEBUG")>]
    static member log(x,y) = printfn x y

您需要切换到元组形式以允许重载并使用元组形式,因为咖喱的东西不能被重载

于 2015-11-19T10:48:25.100 回答