魔术sprintf功能 - 如何包装?

时间:2014-03-31 12:00:40

标签: f#

我正在尝试打包sprintf函数。这是我的尝试:

let p format args = "That was: " + (sprintf format args)

let a = "a"
let b = "b"

let z1 = p "A %s has invalid b" a 

这似乎有效,输出是

val p : format:Printf.StringFormat<('a -> string)> -> args:'a -> string
val a : string = "a"
val b : string = "b"
val z1 : string = "That was: A a has invalid b"

但它不适用于多个arg:

let z2 = p "A %s has invalid b %A" a b

我遇到编译时错误:

let z2 = p "A %s has invalid b %A" a b;;
---------^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(7,10): error FS0003: This value is not a function and cannot be applied

如何创建一个可以使用任意数量的args的单个函数?

UPD 即可。托马斯建议使用

let p format = Printf.kprintf (fun s -> "This was: " + s) format

确实有效。这是一个例子

let p format = Printf.kprintf (fun s -> "This was: " + s) format

let a = p "something like %d" 123
// val p : format:Printf.StringFormat<'a,string> -> 'a
// val a : string = "This was: something like 123"

但问题是我的函数的主要目的是除了formatring之外做一些工作,所以我尝试使用建议的代码如下

let q format = 
    let z = p format // p is defined as suggested
    printf z // Some work with formatted string

let z = q "something like %d" 123

它不再起作用了:

  let z = q "something like %d" 123;;
  ----------^^^^^^^^^^^^^^^^^^^

stdin(30,15): error FS0001: The type ''c -> string' is not compatible with the type 'Printf.TextWriterFormat<('a -> 'b)>'

我该如何解决?

1 个答案:

答案 0 :(得分:6)

要使其正常工作,您需要使用currying - 您的函数p需要获取format并返回printf函数之一返回的函数(可以是带有一个或多个参数的函数。)

使用sprintf无法完成此操作(因为那时您必须显式传播参数。但是,您可以使用kprintf continuation 作为第一个参数::

let p format = Printf.kprintf (fun s -> "This was: " + s) format

使用格式化字符串调用continuation,因此您可以在返回之前使用生成的字符串执行任何操作。

编辑:要回答您的扩展问题,诀窍是将所有额外的工作放入续篇:

let q format = 
  let cont z =
    // Some work with formatted string
    printf "%s" z 
  Printf.kprintf cont format