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

Cle*_*ker 6 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
Run Code Online (Sandbox Code Playgroud)

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

"这个值不是一个功能,不能应用."

那么我做错了什么?

Dax*_*ohl 7

实际上更多的是扩展注释,但是通过使用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
Run Code Online (Sandbox Code Playgroud)

或者甚至更好,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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这样就不会有人偶然输入"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
Run Code Online (Sandbox Code Playgroud)

有了这个,您可以根据需要轻松使用部分应用程序来制作专门的功能:

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
Run Code Online (Sandbox Code Playgroud)

这是函数式编程的好处,就是它很容易混合和匹配.

当然,它很简单,你甚至可能不关心功能.呼叫let x = List.fold (*) 1 [1..4]内联几乎更简单.功能优先的语言往往很好,也很简洁.


Mar*_*ann 6

在这部分代码中:

let rec sum = 
    if n<1 then 0
    else n + sum(n-1)
Run Code Online (Sandbox Code Playgroud)

sum被定义为一个值,因为它不带参数.第三行尝试将其称为函数(sum(n-1)),这是不可能的,因为它不是函数.

在函数中添加一个参数,例如

let rec sum x = 
    if x<1 then 0
    else x + sum(x-1)
Run Code Online (Sandbox Code Playgroud)

在这里我取得了自由,并n在那个功能体中取而代之x,虽然我不知道这是不是你想做什么.但它会编译.


Max*_*Max 5

前缀:我不是F#专家,比我更了解的人可能能够提供更完整的答案.

这里有几件事需要解决:

  1. let rec sum = 缺少参数变量声明.
  2. printfn "%A" product(和sum的一个)是打印函数,而不是值.要更正此问题,您需要使用参数调用该函数.
  3. 定义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)
Run Code Online (Sandbox Code Playgroud)

这是电话:

let x = addormult (4, "multiply")
Run Code Online (Sandbox Code Playgroud)

这给了我这个价值:

product is 24
Run Code Online (Sandbox Code Playgroud)