此值不是函数且无法应用F#

时间:2016-08-10 19:45:21

标签: f#

我一直在尝试用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

但是,每次我尝试运行此功能时,都会收到错误

  

“此值不是函数,无法应用。”

那么我做错了什么?

3 个答案:

答案 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#专家,比我更了解情况的人可以提供更完整的答案。

这里有几件事需要解决:

  1. let rec sum =缺少参数变量声明。
  2. printfn "%A" product(和sum)将打印函数,而不是值。要纠正这个问题,您需要使用参数调用该函数。
  3. n元组值和递归值定义addormult可能会导致问题 - 尽管我不确定F#如何处理这样的情况下的作用域。
  4. 这是这些变化后的“倍增”版本:

    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