3

I'm very new to F# so I have been trying to sum all the elements(double integers) line in a text file to print out year and the total number of elements.

(sample from text file):

2010    **(the elements)->** 1.07   1.56    1.74    3.84    6.8 7.89    9.2 3.46    1.67    2.22    2.49    2.81

However, here is my recursion function to sum all the elements. I get the big error in the main with the explanation in the codes below.

let rec sum values:double list =
    if values = [] then
        []
    else
        values.Head + sum values.Tail

let main argv =
    // read entire file as list of strings:
    let file = ReadFile "rainfall-midway.txt"

    let (year, values) = ParseLine file.Head
    printfn "%A: %A" year (sum [values]) // values gets the error which i cannot understand at all.

Error 1 The type 'float list' does not support the operator '+'

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
CR9191
  • 51
  • 1
  • 7

1 Answers1

4

If you're just trying to get the work done List.sum is easy and won't overflow the stack.

Gustavo has given a good start but if you're summing many, many values you may overflow the stack. You didn't mention how many values you might need to some but if it were enough to overflow the stack you would want to switch to a tail-recursive implementation (see tail call and F# Tail Recursive Function Example):

let sum (values: double list) =

    let rec sum values accum =

        match values with
        | [] -> accum
        | head :: tail -> sum tail (accum + head)

    sum values 0.0

With this implementation I can successfully sum a list of a million values or more without overflowing the stack.

If you'd like to go further with your understanding you might check out the source code for List.fold as it is a more generalized way of applying a function (even (+)) over a list.

The implementation of List.sum makes use of Seq.sum which shows accumulating a value over a sequence that doesn't necessarily require an actual container like List, but's that's clearly outside the stated problem.

Community
  • 1
  • 1
Curt Nichols
  • 2,757
  • 1
  • 17
  • 24
  • This one actually works! Let's say, I want to print out the average of each element, would this work? let sum (values: double list) = let rec sum values accum = match values with | [] -> accum | head :: tail -> sum tail (accum + head) / 12.0 sum values 0.0 – CR9191 Feb 13 '15 at 01:52
  • Well, you probably wouldn't want to call it `sum`. :) You know exactly how many items are in a List with List.length, so you wouldn't need to hard-code it. Also, if you drop the division out of the recursive part you'll divide 1 time rather than N; in that case, you can just reuse your sum function within your averaging function. Also, take care with floating point issues around small or large numbers (depending on the nature and quantity of the values your playing with). – Curt Nichols Feb 13 '15 at 19:58