Nats De Nats De - 2 months ago 17
C# Question

Need Help Converting some F# code to C#

I am doing a Machine Learning using F# book. I am converting the F# code to C# and doing the tutorials as I do not understand F# that much. I really got stuck in a part of code and wonder if someone can tell me how to write the code in c#. Even just the explanation of what the code does in F# would be helpful.. The code I am stuck is

let tokenScore (group:DocsGroup) (token:Token) =
if group.TokenFrequencies.ContainsKey token
then log group.TokenFrequencies.[token]
else 0.0

let score (document:TokenizedDoc) (group:DocsGroup) =
let scoreToken = tokenScore group
log group.Proportion +
(document |> Seq.sumBy scoreToken)

I'm really stuck with the

let scoreToken = tokenScore group
log group.Proportion +
(document |> Seq.sumBy scoreToken)

This is the tutorial in the Machine Learning Projects for .Net Developers - Chapter 2. If you can help me that would be great. Thanks in advance

Answer Source

F# functions are curried. That means that if a function is declared with two parameters, and you call it with just one parameter, the result is another function, of one parameter. Here's an example:

let add x y = x + y
let n = add 2 3  // Now n has the value 5
let addFive = add 5  // This is a *function* that takes one parameter
let altAddFive y = add 5 y  // Another way to define the same thing
let result = addFive 3  // Now result has the value 8
let altResult = altAddFive 3  // This one also has the value 8

So in the score function, the name scoreToken now refers to a function that takes one parameter, and then calls tokenScore with two parameters: group, and the value it was just passed. In other words, the definition of scoreToken could have been written as:

let scoreToken token = tokenScore group token

And that would have been the same thing.

Now for the next line. First, log is the natural logarithm function, usually written as ln in mathematical notation. It takes a single floating-point number, and returns a floating-point number. The rules of operator precedence in F# are that function calls are higher precedence than operators, so log 3.0 + 5.0 would be interpreted as (log 3.0) + 5.0, which would not be the same value as log 8.0. Therefore, the following lines:

log group.Proportion +
(document |> Seq.sumBy scoreToken)

are equivalent to this:

let score1 = log group.Proportion
let score2 = document |> Seq.sumBy scoreToken
score1 + score2

Finally, the document |> Seq.sumBy scoreToken line may also be confusing you. There are two parts to it. First, Seq.sumBy is the equivalent of the two-parameter version of the LINQ Sum method, but the parameter order in F# is the opposite of the one in C#. The F# Seq.sumBy function takes two parameters; first, the function that should be applied to each element to produce a value, and second, the sequence of elements. I.e., if you were calling it without that |> operator, it would look like this:

Seq.sumBy scoreToken document

This would go through the document sequence (which is of type TokenizedDoc and, given the way it's used, clearly can be treated as a sequence of tokens). For each token in the document, the scoreToken function would be called (if you'll remember, calling scoreToken t, where t is some token, is the same as calling tokenScore group t). That call would produce a floating-point value. Finally, all the floating-point values will be added together to produce the final score.

However, in F#, it's traditional to use the "pipe" operator |> when summing sequences or doing similar things: document |> Seq.sumBy scoreToken is exactly equivalent to Seq.sumBy scoreToken document. The |> operator is rather well explained in the answer to another SO question so I won't duplicate that answer here.

So what this function is doing is taking the natural log of the group.Proportion value, and adding it to the score of each token in the document. The result of this addition is the last expression in the function, so that's the result of the function: in F#, unlike C#, you don't need to type return at the end of functions. (The return keyword has a different meaning in F#, which I won't get into now as that's a whole different topic).