Zazaeil
Zazaeil

Reputation: 4119

Currying issues with F#. What is the right way to attach functions to the type?

I can't understand what is wrong with following bit of code:

let toClass (problem:Problem<'a>) (classID:int) (items:'a list) =
        let newFreqTable = (problem.FreqTables.[classID]).count items
        { problem with FreqTables = newFreqTable :: (problem.FreqTables |> List.filter (fun i -> i.ClassID <> classID)) }
type Problem<'a> when 'a : equality with member this.toClass (classID:int) (items:list<'a>) = toClass this classID items

I have a Problem type which is nothing but a way to group up any number of FreqTables - short for "Frequency tables". So toClass method just takes appropriate freqTable (by classID argument) and returns a new one - with calculated given items.

let typeIndependentCall = toClass p 0 ["word"; "word"; "s"] // this works perfectly

let typeDependentCall = typeIndependentCall.toClass 1 ["word"; "s"] 
// gives an error: "One or more of the overloads of this method has 
// curried arguments. Consider redesigning these members to take 
// arguments in tupled form".

I am pretty new to F# and functional programming. What is the right way to attach behavior to my type?

Upvotes: 4

Views: 265

Answers (1)

Reed Mullanix
Reed Mullanix

Reputation: 108

In F# there are 2 main ways of passing arguments to a function: curried and tupled. The curried form is what you are using in your code above, and has a few key benefits, the first and foremost being partial application.

For example, instead of thinking of

fun add a b = a + b

as a function that takes in 2 arguments and returns a value, we can think of it as a function of one argument that returns a function that with one argument. This is why the type signature of our function is

Int -> Int -> Int

or, more clearly,

Int -> (Int -> Int)

However, when overloading methods, we can only use the tupled argument form

(Int, Int) -> Int

The reason for this is for optimization, as is discussed here

To get your code to work, use

type Problem<'a> when 'a : equality with member this.toClass (classID:int, items:list<'a>) = toClass this classID items

and call it like such:

let typeDependentCall = typeIndependentCall.toClass(1, ["word"; "s"]) 

Upvotes: 1

Related Questions