For example, it's the heart of the virtual DOM in React. Pure functions create an entirely new (no mutation) virtual DOM, and then something at the "impure boundary" applies this to the actual, messy, mutable DOM of the browser.
With a little thought you can probably find several other well-known examples.
Testing every teeny tiny piece of a program is just stupid, and leads to more test code than product code, to no real benefit. (Java bean [blech!] getter/setter pairs, I'm looking at you!) ... Particularly very low level details that may end up being thrown out tomorrow morning after you rethink the problem.
OTOH, it's not a bad idea to make sure you test [most] every path, somehow.
At some point, though, sub-assemblies of larger apps are complicated enough to make testing them prudent. I'm not too proud to simply read an environment variable for things such as a server address/socket, though, rather than insisting on D/I. Other times, you gotta do what you gotta do, with complicated mocks and some kind of D/I.
Make sure requirements get tested, but not all [trivial] infrastructure really warrants the make-work.
So what if a dev home brews parser for instance, and you use that to read in files from a legacy system via ftp. You wouldn't test the parser code on its own? You test it all end to end?
If the "parser" has built-in logic to orchestrate remote file retrieval over FTP then DI is warranted, as per the other part of my previous answer.
If you're going to write just one kind of tests, you should write integration tests. But, if you have the time to write both, they will pay dividends.
1. This is overly simplistic. What happens if your IO and logic are by necessity interleaved? Grab X out of DB, grab Y or Z out of DB depending on X's value, etc.? The whole thing just reeks of "ideal case".
2. This is overly complex. All that really needs to be said here is "pull out your pure code when possible". There's nothing special about F# to enable that. The logic in "tryAcceptComposition" is just a function calling other functions; you can do that in C# or even C. The only advantage F# adds here is the piping syntax, which to me only serves to make the code more obtuse. But I guess you couldn't write a three-part series about a single "extract pure function" op.
(This brings up an interesting thought: ReSharper should come up with a way to let you highlight a function and extract the "obviously pure" tidbits automatically).
If free monads could provide something better than standard DI, and (and this is a big caveat) still retain decent editor integration (autocomplete, go-to-declaration/implementation), then I'd check it out. But my gut feeling says that it'll end up being a leaky abstraction that will need undue patching up just to maintain it.
Free Monads can reify an effectful computation, giving flexibility on how it is interpreted. But they are not really a substitute for a good module system.
What makes me cautious about the concept though is that e.g. `do_x_and_y()` would be interpreted differently than `do_x(); do_y()`, even if they were fundamentally the same. While "so what?" is a perfectly valid response, that little tidbit just makes me feel like, while FM's are a very cool abstraction for something, it's not really ideal for DI. It's just something meant for a different level. The article "The Wrong Abstraction" comes to mind.
That is the tip of the iceberg of free monads. Their full power lies in being able to combine different type sof effects into more powerful, composed effects. E.g. you want to do IO while also processing probability distributions using a probability monad. But they can get pretty hairy. See https://youtu.be/qaAKRxO21fU for the gory details.
(** Type-safe IDs using a phantom type. *)
module Id =
type 'a t = private T of uint64
let of_uint64 u = T u
let to_uint64 (T u) = u
(** A domain type. *)
module User =
type t = private { id : t Id.t; name : string; age : int }
let make uid name age : t = ...
...
(** Users service typeclass. *)
module User_service =
type t =
{ get_by_id : User.t Id.t -> User.t Async
add : User.t -> unit Async
rename : string -> User.t Id.t -> unit Async }
let db : t =
{ get_by_id = fun uid -> ...
add = fun u -> ...
rename = fun name uid -> ... }
let test : t =
Now, injecting a user service dependency into any function is equivalent to passing in a parameter of type `User_service.t`.As for free monads, I don't think F# will make them easy. If you notice, one commenter in that GitHub discussion mentioned they were doing a lot of copy-pasting to implement FMs. Imho that's a bad sign.
The special thing about F# is a partial function application that is probably missing in C#.
I like it in certain purely functional data crunching routines, where it is idiomatic and can often make the code more generic and more intentional, but I've never had much luck doing DI this way. YMMV.
Wrong language, but here is an example of a mechanism to partially apply the trailing arguments, rather than the more customary leading arguments: http://ramdajs.com/docs/#partialRight
And finally, if something in the middle is the thing that needs to be nailed down, you can simply write a one liner function to provide the fixed thing and pass in the rest. (not really PFA any more at that point, but it will get the job done)
> When you inject impure operations into an F# function, that function becomes impure as well. Dependency injection makes everything impure, which explains why it isn't functional.
If you pass the dependencies as parameters in the tryAcceptComposition function, the Post would have to know its dependencies and we would be back to the initial state.
I would like to know the whole example he showed before using this model to see how this scale for more than one function.