Posted in:

If like me you’re a fan of LINQPad, you’ll be familiar with the Dump method. This lets you easily output any value to the Results pane.

So if you had a C# LINQ expression like this:

"1,2,3,4,5,6"
    .Split(',')
    .Select(int.Parse)
    .Select(x => x * x)
    .Select(x => x.ToString())
    .Aggregate("", (x,y) => x.Length == 0 ? y : x + "," + y)
    .Dump();

you’d see the following in the Results pane:

1,4,9,16,25,36

You can also attach a name to a call to Dump:

.Dump("Result");

which gives you an output like this:

image

Even nicer is the fact that you can insert calls to Dump at any point in the pipeline, which is great for debugging LINQ pipelines. So if we do this:

"1,2,3,4,5,6"
    .Split(',')
    .Select(int.Parse)
    .Dump("integers")
    .Select(x => x * x)
    .Dump("squares")
    .Select(x => x.ToString())
    .Aggregate("", (x,y) => x.Length == 0 ? y : x + "," + y)
    .Dump("Result");

… then in the results pane we get the following nicely formatted output:

image

But can we use this in F#? If we try a naive conversion we find that we can’t use a named Dump for our result, and we can’t insert calls to Dump in the pipeline, as the F# compiler can’t easily be persuaded to select the correct overload. All we can do is pipe the final result into an unnamed Dump. And that’s because Dump really is a C# extension method, whose method signature is not a good fit for F# partial application.

"1,2,3,4,5,6"
    .Split(',')
    |> Seq.map int
//    |> Dump "integers"
    |> Seq.map (fun x -> x * x)
//    |> Dump "squares"
    |> Seq.map (sprintf "%d")
    |> String.concat ","
    |> Dump // "Result"

The good news is that we can make a couple of simple helper methods to restore the ability to use named dumps at any point. I’ve created one called DumpAs, which can be placed at the end of your pipeline as it returns unit, and one called Peek which is designed to go in the middle of your pipeline, as it returns the input sequence unchanged:

let DumpAs (name:string) x =
    x.Dump name
    
let Peek (name:string) x =
    x.Dump name
    x

"1,2,3,4,5,6"
    .Split(',')
    |> Seq.map int
    |> Peek "integers"
    |> Seq.map (fun x -> x * x)
    |> Peek "squares"
    |> Seq.map (sprintf "%d")
    |> String.concat ","
    |> DumpAs "Result"

Hope someone finds this useful, and as always, let me know in the comments if there is a better way to solve this.

Want to learn more about LINQ? Be sure to check out my Pluralsight course LINQ Best Practices.

Comments

Comment by Robert Kerr

Definitely useful. Thanks!

Robert Kerr
Comment by Mark Ashley Bell

Simple but effective! Very useful, thanks.

Mark Ashley Bell
Comment by Kevin McFarlane

Nice. Thanks. Just saved to MyQueries.

Kevin McFarlane