1 people like it.

A ksprintf with optional formatting

A ksprintf implementation that optionally formats the string. Naive microbenchmarks are provided to demonstrate potential performance gains. See also https://github.com/eiriktsarpalis/TypeShape/blob/d782bcd7fd32b1899c1c95ba933da0ae5e0bb4eb/samples/ksprintf.fsx

Implementation

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
open System
open TypeShape
open TypeShape_Utils

// generates an "ignore" function
// for types of shape 'T1 -> 'T2 -> ... -> 'Tn -> unit
let rec mkIgnore<'T> () : 'T =
    cache.GetOrAdd mkIgnoreAux

and private mkIgnoreAux<'T> () : 'T =
    match shapeof<'T> with
    | Shape.Unit -> unbox ()
    | Shape.FSharpFunc s ->
        s.Accept { new IFSharpFuncVisitor<'T> with
            member __.Visit<'Dom,'Cod> () =
                let ignoreCod = mkIgnore<'Cod>()
                unbox(fun (_ : 'Dom) -> ignoreCod) }
    | _ -> failwithf "Type %O is not a unit arrow!" typeof<'T>

and private cache : TypeCache = new TypeCache()

let ksprintf' (kontOpt : (string -> unit) option) fmt =
    match kontOpt with
    | None -> mkIgnore ()
    | Some kont -> Printf.ksprintf kont fmt

ksprintf' (Some System.Console.WriteLine) "%s=%d" "key" 42

Performance

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
#time "on"

// formatting off
// Real: 00:00:00.161, CPU: 00:00:00.156, GC gen0: 99, gen1: 0, gen2: 0
for i = 1 to 1000000 do
    ksprintf' None "Foo=%s, Bar=%d, Baz=%O" "foo" 42 System.ConsoleColor.Red

// formatting on
// Real: 00:00:01.733, CPU: 00:00:01.750, GC gen0: 316, gen1: 0, gen2: 0
for i = 1 to 1000000 do
    ksprintf' (Some ignore) "Foo=%s, Bar=%d, Baz=%O" "foo" 42 System.ConsoleColor.Red

let value = ([1..5],Some "42")

// formatting off
// Real: 00:00:00.101, CPU: 00:00:00.109, GC gen0: 80, gen1: 0, gen2: 0
for i = 1 to 1000000 do
    ksprintf' None "%A" value

// formatting on
// Real: 00:07:14.970, CPU: 00:07:11.796, GC gen0: 28445, gen1: 43, gen2: 4
for i = 1 to 1000000 do
    ksprintf' (Some ignore) "%A" value
namespace System
module TypeShape
module TypeShape_Utils
val mkIgnore : unit -> 'T

Full name: Script.mkIgnore
val private cache : TypeCache

Full name: Script.cache
member TypeCache.GetOrAdd : factory:(unit -> 'T) -> 'T
val private mkIgnoreAux : unit -> 'T

Full name: Script.mkIgnoreAux
val shapeof<'T> : TypeShape<'T>

Full name: TypeShape.shapeof
module Shape

from TypeShape
active recognizer Unit: TypeShape -> unit option

Full name: TypeShape.Shape.( |Unit|_| )
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
active recognizer FSharpFunc: TypeShape -> IShapeFSharpFunc option

Full name: TypeShape.Shape.( |FSharpFunc|_| )
val s : IShapeFSharpFunc
abstract member IShapeFSharpFunc.Accept : IFSharpFuncVisitor<'R> -> 'R
type IFSharpFuncVisitor<'R> =
  interface
    abstract member Visit : unit -> 'R
  end

Full name: TypeShape.IFSharpFuncVisitor<_>
val ignoreCod : 'Cod
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
Multiple items
type TypeCache =
  new : unit -> TypeCache
  member Commit : manager:RecTypeManager -> unit
  member CreateRecTypeManager : unit -> RecTypeManager
  member GetOrAdd : factory:(unit -> 'T) -> 'T
  member TryAdd : value:'T -> bool
  member TryFind : unit -> 'T option
  member TryFind : t:Type -> obj option
  member TryGetValue : result:byref<'T> -> bool
  member TryGetValue : t:Type * result:byref<obj> -> bool

Full name: TypeShape_Utils.TypeCache

--------------------
new : unit -> TypeCache
val ksprintf' : kontOpt:(string -> unit) option -> fmt:Printf.StringFormat<'a,unit> -> 'a

Full name: Script.ksprintf'
val kontOpt : (string -> unit) option
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
val fmt : Printf.StringFormat<'a,unit>
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val kont : (string -> unit)
module Printf

from Microsoft.FSharp.Core
val ksprintf : continutation:(string -> 'Result) -> format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.Printf.ksprintf
type Console =
  static member BackgroundColor : ConsoleColor with get, set
  static member Beep : unit -> unit + 1 overload
  static member BufferHeight : int with get, set
  static member BufferWidth : int with get, set
  static member CapsLock : bool
  static member Clear : unit -> unit
  static member CursorLeft : int with get, set
  static member CursorSize : int with get, set
  static member CursorTop : int with get, set
  static member CursorVisible : bool with get, set
  ...

Full name: System.Console
Console.WriteLine() : unit
   (+0 other overloads)
Console.WriteLine(value: string) : unit
   (+0 other overloads)
Console.WriteLine(value: obj) : unit
   (+0 other overloads)
Console.WriteLine(value: uint64) : unit
   (+0 other overloads)
Console.WriteLine(value: int64) : unit
   (+0 other overloads)
Console.WriteLine(value: uint32) : unit
   (+0 other overloads)
Console.WriteLine(value: int) : unit
   (+0 other overloads)
Console.WriteLine(value: float32) : unit
   (+0 other overloads)
Console.WriteLine(value: float) : unit
   (+0 other overloads)
Console.WriteLine(value: decimal) : unit
   (+0 other overloads)
val i : int
type ConsoleColor =
  | Black = 0
  | DarkBlue = 1
  | DarkGreen = 2
  | DarkCyan = 3
  | DarkRed = 4
  | DarkMagenta = 5
  | DarkYellow = 6
  | Gray = 7
  | DarkGray = 8
  | Blue = 9
  ...

Full name: System.ConsoleColor
field ConsoleColor.Red = 12
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val value : int list * string option

Full name: Script.value

More information

Link:http://fssnip.net/7RO
Posted:8 months ago
Author:Eirik Tsarpalis
Tags: printf , typeshape