2
\$\begingroup\$

I was bored, and looking to do something that involved anonymous functions, and it was suggested by @Quill, that I create a summation function. I decided to also include a product function as well to top the whole thing off.

For those who don't know, a summation is usually defined like this:

$$\sum_{n=a}^{b}f(n)$$

And a product is usually defined like this:

$$\prod_{n=a}^{b}f(n)$$

I'd like to know the following things:

  • Am I doing this in a proper functional way?
  • Is there a way to reduce the repetitiveness of the code?
  • Is it okay to use List.fold to multiply all the elements of a list together? Is there a better way?
  • Am I violation any style guidelines?
  • Anything else?

Here's the code:

/// <summary>
/// Find the summation in a specific range, given
/// a specific function.
/// </summary>
let summation func low high =
    let function_result_set: int list = [for x in low..high do yield x |> func]
    let result = function_result_set |> List.sum
    result

/// <summary>
/// Find the product in a specific range, given
/// a specific function.
/// </summary>
let product func low high =
    let function_result_set: int list = [for x in low..high do yield x |> func]
    let result = function_result_set |> List.fold (*) 1
    result

And finally, here's a few tests:

[<EntryPoint>]
let main argv =
    System.Console.WriteLine(summation (fun n -> n) 1 10)
    System.Console.WriteLine(product (fun n -> n) 1 10)
    System.Console.ReadKey() |> ignore
    0

And here's the desired output from the above tests:

55
3628800
\$\endgroup\$
  • \$\begingroup\$ Are products like doing factorials the opposite way so it acts more like summation? \$\endgroup\$ – KingCodeFish Oct 14 '15 at 22:22
  • \$\begingroup\$ @KingCodeFish A product is like a summation, except you're doing multiplication, rather than addition. \$\endgroup\$ – Ethan Bierlein Oct 14 '15 at 22:28
  • \$\begingroup\$ @KingCodeFish Think of it like 1 * 2 * 3 .... 9 * 10 rather than 1 + 2 + 3 ... 9 + 10. \$\endgroup\$ – Ethan Bierlein Oct 14 '15 at 22:29
  • \$\begingroup\$ Yes, I understand that. I was just wondering if it's like doing factorials backwards. \$\endgroup\$ – KingCodeFish Oct 14 '15 at 22:49
  • \$\begingroup\$ @KingCodeFish No, I don't think so. \$\endgroup\$ – Ethan Bierlein Oct 14 '15 at 22:49
4
\$\begingroup\$

Starting with summation,

let summation func low high =
    let function_result_set: int list = [for x in low..high do yield x |> func]
    let result = function_result_set |> List.sum
    result

First of all, we can remove result

let summation func low high =
    let function_result_set: int list = [for x in low..high do yield x |> func]
    function_result_set |> List.sum

Next, we don't need to construct a list containing func(low) .. func(high); we can instead operate over a sequence, meaning we don't have to have all those values in memory at once.

let summation func low high =
    let function_result_set = Seq.map func { low .. high }
    function_result_set |> Seq.sum

Now we can make it a bit more succinct

let summation func low high =
    Seq.map func { low .. high } |> Seq.sum

Finally, we can make it more generic by using statically resolved type parameters. At the moment, if we have a call to summation like this:

printfn "%d" <| summation id 1 10

then summation will be constrained to be of type (int -> int) -> int -> int -> int. We can fix this by making the function inline:

let inline summation func low high =
    Seq.map func { low .. high } |> Seq.sum

Now summation has type ('a -> 'b) -> 'a -> 'a -> 'b and the following code will compile:

printfn "%d" <| summation id 1 10
printfn "%f" <| summation id 1.0 10.0

Similar comments hold for product, but with two additional things:

  • To make it generic we need to get the One property of the type ^a, and
  • I've used the checked version of * to check for overflow
let inline product func low high : ^a =
    Seq.map func { low .. high } |> Seq.fold Checked.(*) LanguagePrimitives.GenericOne< ^a >
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.