Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functions vs methods

Tags:

f#

I'm very new to F#. One of the first things I noticed was that collection operations are defined as functions rather than as methods.

As an experiment, I defined a couple of methods on list:

type List<'a> with
    member this.map f = List.map f this
    member this.filter f = List.filter f this

Then, given these helpers:

let square x = x * x

let isEven n = n % 2 = 0

here's an example of using the methods:

[1 .. 10].filter(isEven).map(square)

And here's the traditional way:

[1 .. 10] |> List.filter isEven |> List.map square

So concision clearly wasn't a reason to choose functions over methods. :-)

From a library design perspective, why were functions chosen over methods?

My guess is that it's because you can pass List.filter around, but can't really pass the filter method around unless it's "tied" to a list or wrapped in an anonymous function (i.e. (fun (ls : 'a list) -> ls.filter) effectively turns the filter method back into a function on list).

However, even with that reason, it seems the most common case of invoking an operation directly would give favor to methods since they are more concise. So I'm wondering if there's another reason.

Edit:

My second guess is function specialization. I.e. it's straightforward to specialize List.filter (e.g. let evens List.filter isEven). It seems more verbose to have to define an evens method.

like image 313
dharmatech Avatar asked Dec 27 '22 08:12

dharmatech


1 Answers

What functions have over methods is function specialization and the easy factoring it enables.

Here's the example expression involving functions:

let square x = x * x

let isEven n = n % 2 = 0

[1 .. 10] |> List.filter isEven |> List.map square

Let's factor out a function called evens for filtering evens:

let evens = List.filter isEven

And now let's factor out a function which squares a list of ints:

let squarify = List.map square

Our original expression is now:

[1 .. 10] |> evens |> squarify

Now let's go back to the original method based expression:

[1 .. 10].filter(isEven).map(square)

Factoring out a filter on evens isn't as trivial in this case.

like image 90
dharmatech Avatar answered Jan 03 '23 16:01

dharmatech