我一直在尝试用F#编写一个程序,它接受两个值(一个元组):一个数字和一个字符串。根据字符串是否告诉程序添加或乘法,它将使用从1到该数字的所有整数(即1..n)添加或乘以输入数字。
这是代码
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
但是,每次我尝试运行此功能时,都会收到错误
“此值不是函数,无法应用。”
那么我做错了什么?
答案 0 :(得分:6)
在这部分代码中:
let rec sum =
if n<1 then 0
else n + sum(n-1)
sum
被定义为值,因为它不带参数。第三行尝试将其称为函数(sum(n-1)
),这是不可能的,因为它不是函数。
为函数添加一个参数,例如
let rec sum x =
if x<1 then 0
else x + sum(x-1)
在这里,我采取了自由,用n
替换了该函数体中的x
,尽管我不知道这是不是你想要做的。但它会编译。
答案 1 :(得分:6)
更多的是扩展评论,但使用fold
函数可以简化整个代码。
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
甚至更好,在范围之外定义getOp
,因为它通常适用。
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
也是尾递归的,确保你不会超过大N的堆栈大小限制。在F#中,很多时候你做递归时,已经有一个标准的库函数可以做你的事了需要。或者如果没有,有时最好从函数中提取“一般”递归,然后根据它实现特定的东西。
现在,请注意字符串不是传达意图的最佳方式。最好使用歧视联盟来传达您的操作:
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
这样就不会有人偶然输入“mutliply”并获得意想不到的回报值。
但实际上没有理由限制只有两个操作。任何操作都可以直接使用:
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
有了这个,您可以根据需要轻松使用部分应用程序来制作专门的功能:
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
这对于函数式编程来说是件好事,就是它很容易混合和匹配。
当然,这很简单,你甚至可能不关心功能。只需内联调用let x = List.fold (*) 1 [1..4]
即可。功能优先的语言往往很好,也很简洁。
答案 2 :(得分:5)
前缀:我不是F#专家,比我更了解情况的人可以提供更完整的答案。
这里有几件事需要解决:
let rec sum =
缺少参数变量声明。printfn "%A" product
(和sum)将打印函数,而不是值。要纠正这个问题,您需要使用参数调用该函数。n
元组值和递归值定义addormult
可能会导致问题 - 尽管我不确定F#如何处理这样的情况下的作用域。这是这些变化后的“倍增”版本:
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)
这是电话:
let x = addormult (4, "multiply")
这给了我这个价值:
product is 24