Can I use StringFormat as TextWriterFormat? kfprintf / kprintf usage - f#

I've got function to log to console
Printf.kprintf
(printfn
"[%s][%A] %s"
<| level.ToString()
<| DateTime.Now)
format // fprint to System.Console.Out maybe
but it's using Printf.StringFormat as format and now I want to follow same logic and print it to file.
So I try
Printf.kfprintf
(fun f ->
fprintfn file "[%s][%A] "
<| level.ToString()
<| DateTime.Now
) file (format)
And there are two things I can't understand. Why there is unit -> 'A instead of string -> 'A ? How should I use it? And Can I use my StringFormat here as TextWriterFormat ?
Another trouble with this is that with first snippet I inherit format to string -> 'Result thing but in kfprintf I can't do it because there is unit -> 'Result and format message appears before [x][x] stuff. I guess I can somehow inherit format to f but I can't find good example, the only I found is part of F# compiler:
[<CompiledName("PrintFormatToTextWriter")>]
let fprintf (os: TextWriter) fmt = kfprintf (fun _ -> ()) os fmt
[<CompiledName("PrintFormatLineToTextWriter")>]
let fprintfn (os: TextWriter) fmt = kfprintf (fun _ -> os.WriteLine()) os fmt
But how can I use this unit ? How can I post message after my message?

I don't think you need to use Printf.kfprintf, you can carry on using Printf.kprintf as the inner fprintfn uses the TextWriter.
let logToWriter writer level format =
Printf.kprintf (fprintfn writer "[%s][%A] %s"
<| level.ToString()
<| System.DateTime.Now) format
Also see this for an example of using Printf.kfprintf.

Related

final output of Result, in F#

This seems like a question that has an ultra simple answer, but I can't think of it:
Is there a built in method, within Result, for:
let (a: Result<'a, 'a>) = ...
match a with
| Ok x -> x
| Error e -> e
No, because this function requires the Ok type and the Error type to be the same, which makes Result less general.
No, there isn't any function which will allow you to do so. But you can easily define it:
[<RequireQualifiedAccess>]
module Result =
let join (value: Result<'a, 'a>) =
match value with
| Ok v -> v
| Error e -> e
let getResult s =
if System.String.IsNullOrEmpty s then
Error s
else
Ok s
let a =
getResult "asd"
|> Result.join
|> printfn "%s"
It doesn't make Result less general (as said by #brianberns), because it's not an instance member. Existence of Unwrap doesn't make Task less general
Update
After more scrupulous searching inside FSharpPlus and FSharpx.Extras I've found necessary function. It's signature ('a -> 'c) -> ('b -> 'c) -> Result<'a,'b> -> c instead of Result<'a, 'a> -> 'a and it's called Result.either in both libraries (source 1 and source 2). So in order to get value we may pass id as both parameters:
#r "nuget:FSharpPlus"
open FSharpPlus
// OR
#r "nuget:FSharpx.Extras"
open FSharpx
getResult "asd"
|> Result.either id id
|> printfn "%s"
Also it's may be useful to define shortcut and call it Result.join or Result.fromEither as it's called in Haskell

Writing unit tests against PrintfFormat

I have a type that I'm trying to understand by writing unit tests against it, however I can't reason what to do with PrintfFormat
type ValueFormat<'p,'st,'rd,'rl,'t,'a> = {
format: PrintfFormat<'p,'st,'rd,'rl,'t>
paramNames: (string list) option
handler: 't -> 'a
}
with
static member inline construct (this: ValueFormat<_,_,_,_,_,_>) =
let parser s =
s |> tryKsscanf this.format this.handler
|> function Ok x -> Some x | _ -> None
let defaultNames =
this.format.GetFormatterNames()
|> List.map (String.replace ' ' '_' >> String.toUpperInvariant)
|> List.map (sprintf "%s_VALUE")
let names = (this.paramNames ?| defaultNames) |> List.map (sprintf "<%s>")
let formatTokens = this.format.PrettyTokenize names
(parser, formatTokens)
I feel confident that I can figure everything out but PrintfFormat is throwing me with all those generics.
The file I'm looking at for the code I want to unit test is here for the FSharp.Commandline framework.
My question is, what is PrintfFormat and how should it be used?
A link to the printf.fs file is here. It contains the definition of PrintfFormat
The PrintfFormat<'Printer,'State,'Residue,'Result,'Tuple> type, as defined in the F# source code, has four type parameters:
'Result is the type that your formatting/parsing function produces. This is string for sprintf
'Printer is a type of a function generated based on the format string, e.g. "%d and %s" will give you a function type int -> string -> 'Result
'Tuple is a tuple type generated based on the format string, e.g. "%d and %s" will give you a tuple type int * string.
'State and 'Residue are type parameters that are used when you have a custom formatter using %a, but I'll ignore that for now for simplicity (it's never needed unless you have %a format string)
There are two ways of using the type. Either for formatting, in which case you'll want to write a function that returns 'Printer as the result. The hard thing about this is that you need to construct the return function using reflection. Here is an example that works only with one format string:
open Microsoft.FSharp.Reflection
let myformat (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Printer =
unbox <| FSharpValue.MakeFunction(typeof<'Printer>, fun o ->
box (o.ToString()) )
myformat "%d" 1
myformat "%s" "Yo"
This simply returns the parameter passed as a value for %d or %s. To make this work for multiple arguments, you'd need to construct the function recursively (so that it's not just e.g. int -> string but also int -> (int -> string))
In the other use, you define a function that returns 'Tuple and it needs to create a tuple containing values according to the specified formatting string. Here is a small sample that only handles %s and %d format strings:
open FSharp.Reflection
let myscan (fmt:PrintfFormat<'Printer,obj,obj,string,'Tuple>) : 'Tuple =
let args =
fmt.Value
|> Seq.pairwise
|> Seq.choose (function
| '%', 'd' -> Some(box 123)
| '%', 's' -> Some(box "yo")
| _ -> None)
unbox <| FSharpValue.MakeTuple(Seq.toArray args, typeof<'Tuple>)
myscan "%d %s %d"

Can I call a function by name in f#?

Is there any way to call a function by name in F#? Given a string, I want to pluck a function value from the global namespace (or, in general, a given module), and call it. I know the type of the function already.
Why would I want to do this? I'm trying to work around fsi not having an --eval option. I have a script file that defines many int->() functions, and I want to execute one of them. Like so:
fsianycpu --use:script_with_many_funcs.fsx --eval "analyzeDataSet 1"
My thought was to write a trampoline script, like:
fsianycpu --use:script_with_many_funcs.fsx trampoline.fsx analyzeDataSet 1
In order to write "trampoline.fsx", I'd need to look up the function by name.
There is no built-in function for this, but you can implement it using .NET reflection. The idea is to search through all types available in the current assembly (this is where the current code is compiled) and dynamically invoke the method with the matching name. If you had this in a module, you'd have to check the type name too.
// Some sample functions that we might want to call
let hello() =
printfn "Hello world"
let bye() =
printfn "Bye"
// Loader script that calls function by name
open System
open System.Reflection
let callFunction name =
let asm = Assembly.GetExecutingAssembly()
for t in asm.GetTypes() do
for m in t.GetMethods() do
if m.IsStatic && m.Name = name then
m.Invoke(null, [||]) |> ignore
// Use the first command line argument (after -- in the fsi call below)
callFunction fsi.CommandLineArgs.[1]
This runs hello world when called by:
fsi --use:C:\temp\test.fsx --exec -- "hello"
You can use reflection to get the functions as MethodInfo's by FSharp function name
open System
open System.Reflection
let rec fsharpName (mi:MemberInfo) =
if mi.DeclaringType.IsNestedPublic then
sprintf "%s.%s" (fsharpName mi.DeclaringType) mi.Name
else
mi.Name
let functionsByName =
Assembly.GetExecutingAssembly().GetTypes()
|> Seq.filter (fun t -> t.IsPublic || t.IsNestedPublic)
|> Seq.collect (fun t -> t.GetMethods(BindingFlags.Static ||| BindingFlags.Public))
|> Seq.filter (fun m -> not m.IsSpecialName)
|> Seq.groupBy (fun m -> fsharpName m)
|> Map.ofSeq
|> Map.map (fun k v -> Seq.exactlyOne v)
You can then invoke the MethodInfo
functionsByName.[fsharpFunctionNameString].Invoke(null, objectArrayOfArguments)
But you probably need to do more work to parse your string arguments using the MethodInfo.GetParameters() types as a hint.
You could also use FSharp.Compiler.Service to make your own fsi.exe with an eval flag
open System
open Microsoft.FSharp.Compiler.Interactive.Shell
open System.Text.RegularExpressions
[<EntryPoint>]
let main(argv) =
let argAll = Array.append [| "C:\\fsi.exe" |] argv
let argFix = argAll |> Array.map (fun a -> if a.StartsWith("--eval:") then "--noninteractive" else a)
let optFind = argv |> Seq.tryFind (fun a -> a.StartsWith "--eval:")
let evalData = if optFind.IsSome then
optFind.Value.Replace("--eval:",String.Empty)
else
String.Empty
let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
let fsiSession = FsiEvaluationSession(fsiConfig, argFix, Console.In, Console.Out, Console.Error)
if String.IsNullOrWhiteSpace(evalData) then
fsiSession.Run()
else
fsiSession.EvalInteraction(evalData)
0
If the above was compiled into fsieval.exe it could be used as so
fsieval.exe --load:script_with_many_funcs.fsx --eval:analyzeDataSet` 1

How to manage debug printing in F#

I want to add debug printing to my project with a function having a type signature something like:
bool -> Printf.TextWriterFormat<'a> -> 'a
i.e. it should take a bool indicating whether or not we are in verbose mode, and use that to take the decision about whether to print or not.
For example, lets say dprint : bool -> Printf.TextWriterFormat<'a> -> 'a then I would like this behaviour:
> dprint true "Hello I'm %d" 52;;
Hello I'm 52
val it : unit = ()
> dprint false "Hello I'm %d" 52;;
val it : unit = ()
The idea is that a command line flag can be used to avoid control this output. I also want to avoid a runtime cost in the "not verbose" case. It is possible to define a function that works like this using kprintf:
let dprint (v: bool) (fmt: Printf.StringFormat<'a,unit>) =
let printVerbose (s: string) =
if v then System.Console.WriteLine(s)
fmt |> Printf.kprintf printVerbose
but printing/ignoring a sequence of numbers with List.iter (dprint b "%A") [1..10000] (b \in {true,false}) takes amount 1.5s for both values of b on my machine.
I came up with another method using reflection that builds an appropriately typed function to discard the formatting arguments:
let dprint (v: bool) (fmt: Printf.TextWriterFormat<'a>) : 'a =
let rec mkKn (ty: System.Type) =
if FSharpType.IsFunction(ty) then
let _, ran = FSharpType.GetFunctionElements(ty)
FSharpValue.MakeFunction(ty,(fun _ -> mkKn ran))
else
box ()
if v then
printfn fmt
else
unbox<'a> (mkKn typeof<'a>)
but here the reflection seems too expensive (even more so than that done inside the standard libraries complicated definition of printf sometimes).
I don't want to litter my code with things like:
if !Options.verbose then
printfn "Debug important value: %A" bigObject5
or closures:
dprint (fun () -> printfn "Debug important value: %A" bigObject5)
so, are there any other solutions?
I like your solution using reflection. How about caching it on the type level so that you pay the price of reflection only once per type? For example:
let rec mkKn (ty: System.Type) =
if Reflection.FSharpType.IsFunction(ty) then
let _, ran = Reflection.FSharpType.GetFunctionElements(ty)
// NOTICE: do not delay `mkKn` invocation until runtime
let f = mkKn ran
Reflection.FSharpValue.MakeFunction(ty, fun _ -> f)
else
box ()
[<Sealed>]
type Format<'T> private () =
static let instance : 'T =
unbox (mkKn typeof<'T>)
static member Instance = instance
let inline dprint verbose args =
if verbose then
printfn args
else
Format<_>.Instance
A pragmatist would just use the fast C# formatted printing machinery instead of this. I avoid Printf functions in production code because of the overhead they have, as you point out. But then F# printing definitely feels nicer to use.
My #time results for List.iter (dprint false "%A") [1..10000]:
Original version : 0.85
Original version with reflection : 0.27
The proposed version : 0.03
How about this:
/// Prints a formatted string to DebugListeners.
let inline dprintfn fmt =
Printf.ksprintf System.Diagnostics.Debug.WriteLine fmt
Then you can write:
dprintfn "%s %s" "Hello" "World!"
Debug.WriteLine(...) is marked with [<Conditional("DEBUG")>] so the F# compiler should be able to eliminate the entire statement at compile-time (though you'll have to experiment and check the compiled IL to see if it actually does.
Note that this solution only works if you don't care about changing the verbosity at run-time. If that's the case, you'll have to look for a different solution.
UPDATE : Out of curiousity, I just tried this code (it does work) and the F# 2.0 compiler doesn't compile everything away (even with optimizations on), so the speed is the same whether debugging or not. There might be other ways to get the compiler to eliminate the whole statement to fix the speed issue, but you'll just have to experiment a bit to find out.
Why not use #defines just do
let dprint (fmt: Printf.StringFormat<'a,unit>) =
#if DEBUG
let printVerbose (s: string) =
System.Console.WriteLine(s)
fmt |> Printf.kprintf printVerbose
#else
fun _ -> ()
On my machine the sample test takes 0.002s in the optimised version

F#: Composing sprintf with a string -> unit function to allow formatting

There's information out there on how to do custom processing on a format and its parts. I want to do something a bit simpler, specifically, I want to do something to the effect of:
let writelog : string -> unit = ... // write the string to the log
let writelogf = sprintf >> writelog // write a formatted string to the log
I'm not too surprised that the compiler gets confused by this, but is there any way to get it to work?
The simplest way to define your own function that takes a formatting string like printf is to use Printf.kprintf function. The first argument of kprintf is a function that is used to display the resulting string after formatting (so you can pass it your writelog function):
let writelog (s:string) = printfn "LOG: %s" s
let writelogf fmt = Printf.kprintf writelog fmt
The fmt parameter that is passed as a second argument is the special format string. This works better than jpalmer's solution, because if you specify some additional arguments, they will be directly passed to kprintf (so the number of arguments can depend on the formatting string).
You can write:
> writelogf "Hello";;
LOG: Hello
> writelogf "Hello %d" 42;;
LOG: Hello 42
This works
> let writelog = fun (s:string) -> printfn "%s" s;;
val writelog : string -> unit
> let writelogf arg = sprintf arg >> writelog;;
val writelogf : Printf.StringFormat<('a -> string)> -> ('a -> unit)
> writelogf "hello %s" "world";;
hello world
val it : unit = ()
>
(session is from FSI)
key is in the extra argument to writelogf

Resources