I have been trying to write a program in F# which takes two values (a tuple): a number and a string. Depending on whether the string tells the program to add or multiply, it will add or multiply the input number with all the integers from 1 to that number (i.e. 1..n).
Here is the code
let addormult (n:int, what:string) =
if what = "multiply" then
let rec product n =
if n<1 then 0
else n*product(n-1)
printfn "%A" product
elif what = "sum" then
let rec sum =
if n<1 then 0
else n + sum(n-1)
printfn "%A" sum
However, every time I try to run this function, I get the error
"This value is not a function and cannot be applied."
So what am I doing wrong?
Really more of an extended comment, but the whole of this code can be simplified by using a fold
function.
let addormult (n, what) =
let f = if what = "multiply" then (*) else (+)
List.fold f 1 [1..n]
let x = addormult(4, "multiply") // results in x = 24
let y = addormult(4, "add") // results in y = 10
Or even better, define getOp
outside the scope, since it's going to be generally applicable.
let getOp what = if what = "multiply" then (*) else (+)
let addormult (n, what) = List.fold (getOp what) 1 [1..n]
let x = addormult(4, "multiply") // results in x = 24
let y = addormult(4, "add") // results in y = 10
fold
is also tail-recursive, ensuring you don't exceed the stack size limit for large N. In F#, a lot of times when you do recursion, there's already a standard library function that does what you need. Or if not, sometimes it's better to extract a "general" recursion out of your function and then implement your specific thing in terms of that.
Now, note that strings are not the best way to convey intention here. Far better to use a discriminated union to convey your operation:
type Op = Add | Multiply
let getop = function | Multiply -> (*) | Add -> (+)
let addormult (n, what) = List.fold (getop what) 1 [1..n]
let x = addormult(4, Multiply) // results in x = 24
let y = addormult(4, Add) // results in y = 10
That way there's no chance someone could accidentally type "mutliply" and get an unexpected return value.
But really there's no reason to limit to just two operations. It's straightforward to make this work with any operation:
let doOneToN f n = List.fold f 1 [1..n]
let x0 = doOneToN (*) 4 // results in x0 = 24
let y0 = doOneToN (+) 4 // results in y0 = 10
With this, you can easily use partial application to make specialized functions if you want:
let factorial = doOneToN (*) // the `n` argument is "curried"
let triangularSum = doOneToN (+) // the `n` argument is "curried"
let x1 = factorial 4 // results in x1 = 24
let y1 = triangularSum 4 // results in y1 = 10
That's the nice thing about functional programming, is that it's easy to mix and match things.
Of course it's so simple that you might not even care to make a function. It's almost simpler just to call let x = List.fold (*) 1 [1..4]
inline. Functional-first languages tend to be nice and terse that way.
Prefix: I am no F# expert and someone more knowledgeable than me may be able to provide a more complete answer.
There are a couple of things to fix here:
let rec sum =
is missing a parameter variable declaration.printfn "%A" product
(and the one for sum) are printing the functions, not the values. To correct this, you need to call the function with the arguments.n
for both the addormult
tuple value and the recursive value might cause issues - though I am not sure how F# deals with scoping in a situation like this.This is the "multiply" version after these changes:
let addormult (n:int, what:string) =
if what = "multiply" then
let rec product x =
if x = 1 then 1
else x * product(x-1)
printfn "product is %A" (product n)
And here is the call:
let x = addormult (4, "multiply")
Which gives me this value:
product is 24
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With