Magic sprintf function - how to wrap it?

∥☆過路亽.° 提交于 2019-12-10 17:19:45

问题


I am trying to wrap a call to sprintf function. Here's my attempt:

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

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

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

This seems to work, output is

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"

But it wouldn't work with more than one arg:

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

I get compile-time error:

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

How can I create a single function which would work with any number of args?

UPD. Tomas has suggested to use

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

It works indeed. Here's an example

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"

But the thing is that main purpose of my function is to do some work except for formatring, so I tried to use the suggested code as follows

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

And it doesn't work again:

  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)>'

How could I fix it?


回答1:


For this to work, you need to use currying - your function p needs to take the format and return a function returned by one of the printf functions (which can then be a function taking one or more arguments).

This cannot be done using sprintf (because then you would have to propagate the arguments explicitly. However, you can use kprintf which takes a continuation as the first argument::

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

The continuation is called with the formatted string and so you can do whatever you need with the resulting string before returning.

EDIT: To answer your extended question, the trick is to put all the additional work into the continuation:

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


来源:https://stackoverflow.com/questions/22760998/magic-sprintf-function-how-to-wrap-it

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!