That's an interesting idea - adding a "finally pipeline operator" would complete the try-catch-finally concept. (btw - maybe something like "error catching pipeline operator" is a better name? For short, "catch pipe"?)
Though, thinking more into the details of what a pipeline operator does, I think a finally pipe wouldn't fit very well. Let's take this example:
const parsedFileContents = openFile(...) |> file => file.read() |> content => parseContent(content)
Being a good person, you want to clean up your file resource that you created in the pipe, so you want to tack something like this at the end of the pipeline:
|< file => file.close()
But we quickly realize a couple issues:
- How do we get our hands onto the file object? This file object is scoped to an earlier pipe that wasn't passed through the pipeline. It is possible to carry the file object through the entire pipeline along with the data we're transforming, but that adds a lot of complexity to the pipeline.
- We don't want parsedFileContents to end up getting set to the return value of file.close(), we want it to be what was returned from parsedContent(). (it's possible to do this too, just adds a bit more complexity)
In short, the expression that goes in the finally pipe does not care about its input or output - that expression doesn't really belong as part of the pipeline, and would probably be better expressed with a normal try-finally.