26

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 :-)

schmoopy
  • 6,419
  • 11
  • 54
  • 89
  • 5
    What's wrong with passing 3 functions? – MarcinJuraszek Dec 01 '15 at 03:07
  • Or a record made up of 3 functions – Federico Berasategui Dec 01 '15 at 03:08
  • Very good presentation http://www.slideshare.net/ScottWlaschin/fp-patterns-ndc-london2014 – Ruben Bartelink Dec 02 '15 at 04:38
  • 2
    @MarcinJuraszek - It just feels like the creep of constantly having to add more functions as parameters as needs changes. My OO mind says pass one object so that additional properties (or functions) could be added w/o changing the existing contract/signatures. – schmoopy Dec 02 '15 at 17:29
  • @schmoopy The "creep" you feel is correct and intentional. At some point, adding another parameter may feel so wrong that it will lead you to question the design and perhaps refactor it. This is exactly what should happen as your understanding of the business problems increases. – Kasey Speakman Dec 28 '16 at 17:23

4 Answers4

101

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:

type IDoSomething =
    abstract DoIt : unit -> unit
    abstract DoItMore : unit -> unit
    abstract DoItMost : unit -> unit

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:

let run foo bar baz = List.map foo >> bar >> List.groupBy baz

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 that foo, bar, and baz 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:

type Parity = Even | Odd
let parity i =
    match i % 2 with
    | 0 -> Even
    | _ -> Odd

open System

let tryParse s =
    match Int32.TryParse s with
    | true, i -> Some i
    | _ -> None
let runP = run tryParse (List.choose id) parity

The runP function has the type string 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):

> runP ["Foo"; "1"; "42"; "Bar"; "Baz"; "1337"];;
val it : (Parity * int list) list = [(Odd, [1; 1337]); (Even, [42])]

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)

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 4
    Totally blew my mind. For the record (no pun intended), my background is mainly in OOP, and I'm only relatively recently started learning FP together with F#, with no academic background. totally +1. – Federico Berasategui Dec 01 '15 at 22:58
  • 2
    And if you're looking for more of this level of clarity on F# and other topics, you'll be delighted by [Mark's courses](http://www.shareasale.com/r.cfm?u=1017843&b=611266&m=53701&afftrack=&urllink=www%2Epluralsight%2Ecom%2Fauthor%2Fmark%2Dseemann) – Ruben Bartelink Dec 02 '15 at 04:44
  • This makes sense, the part that i was missing was using partial applications during injection to accomplish what I need - i picked up on this from another comment you made to someone else - thanks Mark! – schmoopy Dec 02 '15 at 20:18
  • Nice answer, but why do you say that passing a record with functions isn't functional? – Tomas Jansson Dec 03 '15 at 07:55
  • 1
    @TomasJansson Based on what's idiomatic in 'leading' Functional languages. In Haskell use typeclasses; in Clojure use protocols; in F# use interfaces. I must admit that I don't know how it's done in Erlang or Scala, though. In general, grouping functions together feels like a bit of smell in most FP languages. Why group functions? Doesn't that smell of coupling? – Mark Seemann Dec 03 '15 at 10:02
  • Not sure I agree with that statement though. You can easily define something like this in haskell `data Something = Something { s :: Integer->String}` which you can instantiate with `let a = Something { s = \y -> "Hello"}` and then have a function taking such a parameter `let doS (Something {s=s'}) = s' 5` and call it with `doS a`. – Tomas Jansson Dec 04 '15 at 10:35
  • But I do agree that you should avoid interfaces if you can, but use them if it make sense and simplifies things. Also, group functions if it make sense but know that it is coupling things together. But that doesn't mean it is not functional. – Tomas Jansson Dec 04 '15 at 10:37
  • @TomasJansson Where did I say that passing a record with functions isn't Functional? – Mark Seemann Dec 04 '15 at 11:48
  • @MarkSeemann for completeness, Scala uses traits, which are the logical equivalent to abstract classes in C#, as they can be partially implemented: http://docs.scala-lang.org/tutorials/tour/traits.html – Ricardo Rodrigues Dec 04 '15 at 16:19
  • You wrote "Right, it isn't Functional, but neither is creating a record of functions." – Tomas Jansson Dec 05 '15 at 21:43
  • @TomasJansson I did. Perhaps I should have written *idiomatic*, or similar. Whether it's Functional depends on whether the functions themselves are pure. – Mark Seemann Dec 06 '15 at 07:36
  • 2
    It's not a biggy, why don't you think it is an idiomatic approact? As long as the functions in the record are pure I still think it is a functional idiomatic approach. Didn't mean to make it sound like a big deal, your answer is excellent! – Tomas Jansson Dec 06 '15 at 23:36
  • 4
    I don't see how this answer avoids my perceived need for a bag of functions. Running a recursive simulation of an options position over a price time series. The simulation needs option functions for: value, delta, vega, vanna, maybe gamma. Those functions come in a family: Black's family, Bachelier family, maybe Kirk family, etc. In some cases the choice is entirely user discretion. Clearly sending BlacksFamily is much better than sending 5 function parameters. How do you make BlacksFamily a function in a nice way? Composition is not relevant. – RomnieEE Jun 30 '16 at 17:55
  • 1
    @RomnieEE I can't say; I'm not familiar with that domain. All I can say is that in my experience, _most_ problems can be decomposed into singular functions/methods. For those cases where you can't, as my answer explains, in F# you have interfaces; in Haskell, you have typeclasses, etcetera. – Mark Seemann Jun 30 '16 at 20:11
  • @RomnieEE I agree. Especially if you need e.g. `let calc data (algos:AlgoFamily seq) = ...`. The other option, `let calc data deltaAlgos vegaAlgos etc = ...` just to avoid interfaces is silly. I actually *like* the record-of-functions option, as it allows `with` syntax for easy runtime OCP rather than needing compile-time inheritance. Sometimes interface inheritance is easier though, e.g. when you need `IDisposable`. – Dax Fohl Dec 16 '16 at 12:28
9

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:

type DoSomethingInstruction<'a> =
| DoIt of 'a
| DoItMore of 'a
| DoItMost of 'a

let private mapI f = function
    | DoIt next     -> DoIt     (next |> f)
    | DoItMore next -> DoItMore (next |> f)
    | DoItMost next -> DoItMost (next |> f)

type DoSomethingProgram<'a> =
| Free of DoSomethingInstruction<DoSomethingProgram<'a>>
| Pure of 'a

let rec bind f = function
    | Free x -> x |> mapI (bind f) |> Free
    | Pure x -> f x

let doIt = Free (DoIt (Pure ()))

let doItMore = Free (DoItMore (Pure ()))

let doItMost = Free (DoItMost (Pure ()))

type DoSomethingBuilder () =
    member this.Bind (x, f) = bind f x
    member this.Return x = Pure x
    member this.ReturnFrom x = x
    member this.Zero () = Pure ()

let doDomething = DoSomethingBuilder ()

You can write a small sample program using the doSomething computation expression:

let p = doDomething {
    do! doIt
    do! doItMore
    do! doItMost }

Furthermore, you can 'implement' the 'interface' by writing an interpreter:

let rec interpret = function
    | Pure x -> x
    | Free (DoIt next)     -> printfn "Doing it.";      next |> interpret
    | Free (DoItMore next) -> printfn "Doing it more!"; next |> interpret
    | Free (DoItMost next) -> printfn "DOING IT MOST!"; next |> interpret

You can now run the program:

> interpret p;;
Doing it.
Doing it more!
DOING IT MOST!
val it : unit = ()

This clearly requires more boilerplate code, but all code apart from the interpreter is pure.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
4

Use a Record Type:

type MyFunctions = { 
    DoIt: (unit -> unit); 
    DoItMore: (unit -> unit);
    DoItMost: (unit -> unit);
}

Then you can

type MyController(functions: MyFunctions) =
    let a = functions.DoIt()
    let b = functions.DoItMore()
    let c = functions.DoItMost()

and you can instantiate the record type with references to a module's functions:

module MyModule =
    let doIt() =
        Console.WriteLine("Do It!")

    let doItMore() =
        Console.WriteLine("Do It More!")

    let doItMost() = 
        Console.WriteLine("Do It Most!")

    let myRecord = { 
        DoIt = doIt; 
        DoItMore = doItMore; 
        DoItMost = doItMost; 
    }

    let controller = 
        MyController(myRecord)

Alternatively you might want to just

type MyController(doIt: (unit -> unit), doItMore: (unit -> unit), doItMost: (unit -> unit))
// ... Etc

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.

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • Ha, it never occurred to me to wrap my methods in a type.... agree on the unit() that is why i was asking, it felt wrong. Also even the type seems .. a bit odd, wouldnt this be the same essentially as creating a class? I mean, what would be the recommendation for a CustomerDomain? Would it be a module with a bunch of functions or should it be a type that contains functions? – schmoopy Dec 01 '15 at 03:44
  • @schmoopy domain objects are comprised of data + functionality. Also, an F# `module` is conceptually equivalent to a `static class` in C#, meaning, you can't instantiate it. IMO, it doesn't make sense to use modules as domain objects, I'd rather create a regular type with the relevant properties AND functions. The more immutability you can afford, the better it will be, though sometimes 100% immutability is more trouble than it's worth (for example if you're using serialization or an ORM you can't use immutable types) – Federico Berasategui Dec 01 '15 at 03:46
  • thanks -- that is what I was thinking but was not sure if it was the OO part of the brain that was saying it :-) – schmoopy Dec 01 '15 at 03:53
  • 1
    I wouldn't give up your answer too quickly. My comment above will be buried in the lower rated comments. But sometimes you do need a bag of functions, and the bag will be filled by different choices of family (like greeks functions that come with each option valuation model). Maybe I'm missing it, but I don't see how to make that a function of functions. It's not a matter of composition of functions. – RomnieEE Jun 30 '16 at 18:03
2

Technically, there are at least five different ways to pass multiple functions:

  • as arguments, curried
  • as arguments, tupled
  • as field values of a record type instance
  • as field values (val ...) or properties (concrete or abstract member ...) of a concrete or abstract class type instance
  • as properties (abstract members) of an interface type instance

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."

Marc Sigrist
  • 3,964
  • 3
  • 22
  • 23