I know I will laugh when I see this answer, but for some reason I don't see it.
For some reason it is eluding me how to pass multiple func in one parameter (for lack of better words.)
For instance, lets say I have IDoSomething that has 3 methods:
1.) DoIt()
2.) DoItMore()
3.) DoItMost()
in OO, I would do this:
type MyController(something:IDoSomething) =
let a = something.DoIt()
let b = something.DoItMore()
let c = something.DoItMost()
So, for F# I would have a module with the 3 functions mentioned above. But how would I pass that into my controller? Would I have to pass each as a separate function instead? I kinda feel like I want to pass the whole module hehe :-)
Most of what I wrote in my other answer, I still consider proper and idiomatic for F#. Later, however, I've learned that the use of functions or partial application, while fine, readable, understandable, simple, and idiomatic in a multiparadigmatic language like F#, is, in fact, not strictly functional.
In a nutshell, the problem is that dependencies tend to be impure, and if you 'inject' them into client code, then that client code also becomes impure, because pure code can't call impure code.
In Haskell, you have several options for addressing this problem, but not all of them translate well to F#. One of these alternative do translate, at least to some degree: free monads.
I don't want this answer to come across in a way that free monads is the idiomatic replacement for interfaces in F#, but for the sake of completeness, I'm adding this answer as well:
Using the F# free monad recipe, the OP interface becomes:
You can write a small sample program using the
doSomething
computation expression:Furthermore, you can 'implement' the 'interface' by writing an interpreter:
You can now run the program:
This clearly requires more boilerplate code, but all code apart from the interpreter is pure.
Technically, there are at least five different ways to pass multiple functions:
If and when coupling multiple functions together makes any sense depends on your specific problem domain, and on how much you weigh certain advantages and disadvantages of each approach... not to mention conventions, culture, style and taste. So-called best practices are never universally valid; they are just hints. Pragmatism is the best best practice.
Here is what Expert F# 3.0 says (page 579): "Recommendation: Use Object Interface Types Instead of Tuples or Records of Functions. In Chapter 5, you saw various ways to represent a dictionary of operations explicitly, such as using tuples of functions or records of functions. In general, we recommend that you use object interface types for this purpose, because the syntax associated with implementing them is generally more convenient."
Use a Record Type:
Then you can
and you can instantiate the record type with references to a module's functions:
Alternatively you might want to just
Side note: a lot of
unit
in F# is usually an indication of bad design.Edit: Mark Seemann's answer is the correct answer to this question.
This question seems to come up again and again, and somehow the accepted answer often turns out to be 'a record of functions'. There's no reasonable motivation for doing this. Records are for data. They have structural equality, which is totally destroyed by putting functions into them, since functions don't have structural equality.
Interfaces
So, what's the alternative to interfaces in F#?
Well, if you absolutely must group functions together, F# enables you to define interfaces. Yes: interfaces:
This language feature exists, so if you need an interface, there's no reason to come up with some weird replacement for it.
But, it's not Functional
Right, it isn't Functional, but neither is creating a record of functions.
The question is whether there's a single, ubiquitous Functional way of grouping related functions together. Haskell has type classes and Clojure has protocols (which, to me, look a bit like type classes, but then, I'm hardly a Clojure expert).
F# has neither type classes nor protocols; the closest you get in the language is, again, interfaces.
Functions
All that said, the fundamental building block of Functional Programming is: functions. Sometimes, functions are composed from other functions, or return other functions. We call these higher-order functions.
Idiomatic Functional code is often expressed through higher-order functions. Instead of passing in an interface to a function, pass other functions:
Because of type inference, even such a nonsense example as above compiles. It has the type
('a -> 'b) -> ('b list -> 'c list) -> ('c -> 'd) -> ('a list -> ('d * 'c list) list)
. I have no idea what it does (I just made it up), but the point is thatfoo
,bar
, andbaz
are functions. As an example,foo
is a function of the type'a -> 'b
.Even with such a ridiculous function as
run
, you can apply it, and it may actual make sense:The
runP
function has the typestring list -> (Parity * int list) list
. What does it do? It takes a list of strings, discards those that aren't integers, and groups them by parity (even/odd):So, it turned out to be (sort of) useful after all!
From OOP to FP
In the beginning of this rant, I wrote: "if you absolutely must group functions together". There's a reason I wrote if. Even in OOD, from the Interface Segregation Principle, we know that we shouldn't force a client to depend on functions it doesn't need. Passing a group of functions to a client can easily violate that principle. The more members an interface defines, the bigger the risk of violation.
In addition to that, from the Dependency Inversion Principle follows that "clients [...] own the abstract interfaces" (APPP, chapter 11). In other words, the client states what it needs, and the interface must conform to that; it's not the implementation that defines the interface.
Once you start following these, and the rest of the SOLID principles, you should begin to realise that the more granular you define your interfaces, the better. The logical conclusion is to define all interfaces with only a single method. If a client needs more than one member, you can always pass two interfaces as two arguments, but you can never remove a member from an interface if it's already defined.
That's extensibility in a nutshell: you can extend, but you can't diminish.
In OOD, interfaces should ideally define only a single member, but in Functional Programming, we have a more natural candidate for such polymorphism: a function.
Thus, pass functions as arguments. It's the Functional way to do it.
Edit: See also my other answer (on free monads)