Removing a string using List.reduce (>>) changes the type of showRainbow , and so you get what is not a function, and therefore the pipeline operator cannot call it defaultLabel as an argument.
In the source program, the showRainbow type is a function that turns one CoolLabel into another:
val showRainbow : (CoolLabel -> CoolLabel)
If you delete the line, you will get a list of functions:
val showRainbow : (CoolLabel -> CoolLabel) list
This example does not use functions trivially, so let me explain a little what is happening. Let's start with rainbow , which is a list of colors. Then rainbow |> List.map setLabel turns the list of colors into a list of functions. You can read this as:
rainbow |> List.map (fun color -> setLabel color)
But, setLabel takes two arguments. Here we indicate only the first, so the result is a function that expects CoolLabel and changes its color to the current rainbow color.
As soon as you have a list of functions, List.reduce (>>) compiles them - it creates a new function that calls all of them at the input it receives. Thus, the result is essentially a function:
let resultingFunction input = setLabel "violet" (setLabel "indigo" (setLabel "blue" ( ... (input)))))
Now you can understand why this returns a shortcut with a purple color - it changes the defaultLabel color to red, then to orange, then to yellow, etc. and finally on indigo and then on purple!
If you change setLabel so that it does not ignore the original color, but possibly combine them (by adding lines), then you will see how the setLabel function was called for all colors:
let setLabel msg label = { label with CoolLabel.label = label.label + " " + msg }
The result will be:
> defaultLabel |> showRainbow;; val it : CoolLabel = {label = " red orange yellow green blue indigo violet";}