I always seem to end up writing the same adapter functions over and over again when starting a new project. The functions are usually one or two lines and could easily just be used as lambdas throughout the application. I have found that giving these small functions a name can help make things more succinct. A lot of those functions can be found in FSharpx.Extras, specifically in
You’ve written your application and have a nice clean pipeline to define the flow of your operations. All of a sudden you need to add a side-effect in the middle of that pipeline. It could be a log to file, console, or even send some events. We have some choices on how to handle this. We can break the pipes into multiple blocks with
let expressions and then evaluating the side-effect. There is nothing wrong with this approach, and may be the best solution. In some simple cases we can use the tee function.
let tee (f : 'a -> unit) x = f x x
tee function acts like a plumbing “T” connector allowing the contents to pass through the side-effect without breaking the pipeline. We can see
tee is a higher order function that takes a function as a parameter. It then calls the passed in function with the secondary parameter as its argument. We are disregarding the resulting evaluation and then returning x.
A small example would be adding debug logging.
let processData (outputLogger : 'a -> unit) someKey = someKey |> getData |> transformData |> tee outputLogger |> finalProcessing
We have a
processData function that takes a logging function as an argument. We then wedge the
outputLogger into our pipeline using the
tee adapter function.
We could have used a lambda to hook in the logging. I’ve done that in the past and still on occasion. I do believe there is value in knowing the names of these small and specialized functions. They have one purpose and do it well. I find I don’t have the mental overhead of entering the lambda when coming back to the code at a later date.