繁体   English   中英

F#:如何使用Argument Byref Int调用函数

[英]F#: How to Call a function with Argument Byref Int

我有这个代码:

let sumfunc(n: int byref) =
  let mutable s = 0 
  while n >= 1 do
    s <- n + (n-1)
    n <- n-1
  printfn "%i" s

sumfunc 6

我收到错误:

(8,10): error FS0001: This expression was expected to have type
    'byref<int>'
but here has type
    'int'

所以我可以告诉我这是什么问题,但我不知道如何解决它。 我想我需要以某种方式将数字6指定为byref<int> 我只是不知道如何。 我的主要目标是使n或函数参数可变,以便我可以在函数内部更改和使用它的值。

对你来说这是一个学校作业以及自己做的工作,而不只是问一个归结为“请为我做功课”的问题,这对你有好处。 因为你是诚实的,所以我会给你一个比我原来更详细的答案。

首先,这似乎是一个非常奇怪的任务。 使用while循环和单个局部变量会引导您重新使用n参数,这是一个非常糟糕的主意 作为一般规则,函数永远不应修改自身之外的值 - 这就是您尝试使用byref参数执行的操作。 一旦你经历了足够知道为什么byref是一个坏主意的大部分时间,你经历了足够知道为什么它可能 - 可能 -需要一些时间。 但是,让我通过使用s952163编写的代码向您展示为什么这是一个坏主意:

let sumfunc2 (n: int byref)  =
    let mutable s = 0
    while n >=  1 do
        s <- n + (n - 1)
        n <- n-1
        printfn "%i" s

let t = ref 6
printfn "The value of t is %d" t.contents
sumfunc t
printfn "The value of t is %d" t.contents

这输出:

The value of t is 7
13
11
9
7
5
3
1
The value of t is 0

你在期待吗? 你是否期望t的值改变只是因为你把它传递给了一个函数? 你不应该。 你真的,真的不应该。 函数应尽可能“纯粹” - 在编程术语中的“纯”函数,不会修改自身之外的任何东西 - 因此,如果使用相同的输入运行它两次,它应该每次产生相同的输出

我给你一个方法来尽快解决这个问题,但我会寄我到目前为止已经写的,现在让你看到它。

更新 :现在,这是一个更好的解决方法。 首先,让你的老师报道了递归吗? 如果他没有,那么这里有一个简短的总结:函数可以调用自己,这是解决各种问题的非常有用的技术。 如果您正在编写递归函数,则需要在let之后立即添加rec关键字,如下所示:

let rec sumExampleFromStackOverflow n =
    if n <= 0 then
        0
    else
        n + sumExampleFromStackOverflow (n-1)

let t = 7
printfn "The value of t is %d" t
printfn "The sum of 1 through t is %d" (sumExampleFromStackOverflow t)
printfn "The value of t is %d" t

注意我怎么也没必要做t可变的这段时间。 事实上,我本来可以调用sumExampleFromStackOverflow 7并且它可以工作。

现在,这不使用while循环,因此它可能不是您的老师正在寻找的。 我看到s952163刚刚用不同的解决方案更新了他的答案。 但是你应该尽快习惯递归的想法,因为使用递归将问题分解为单个步骤是解决F#中许多问题的一种非常强大的技术。 所以尽管这不是你现在正在寻找的答案,但这你很快就会寻找的答案。

PS如果您使用过任何帮助,请告诉您的老师您已经这样做了,并告诉他这个问题的URL( http://stackoverflow.com/questions/39698430/f-how-to-call-a-function-with-argument-byref-int )所以他可以阅读你问的内容以及其他人告诉你的内容。 如果他是一位好老师,他不会因为这样做而降低你的成绩; 事实上,他可能因为你如何解决问题而诚实地提出这个问题。 但如果你得到了家庭作业的帮助而你没有告诉老师,1)那是不诚实的,2)从长远来看,你只会伤害自己,因为他会认为你理解一个你可能已经拥有的概念我还明白。

更新2 :s952163建议我告诉你如何使用foldscan功能,我想“为什么不呢?” 请记住,这些都是高级技术,因此您可能无法在需要fold一段时间的情况下获得分配。 fold基本上是一种获取任何列表的方法,并以通用方式进行计算,将列表转换为单个值。 使用fold ,您可以指定三个内容:要使用的列表,计算的起始值以及将执行计算的一个步骤的两个参数的函数。 例如,如果您尝试将所有数字从1加到n ,则“一步”函数将let add ab = a + b (F#中有一个更高级的功能,我正在跳过这个解释,因为你应该一次只学习一件事。通过跳过它,它使add功能简单易懂。)

你使用fold的方式如下:

let sumWithFold n =
    let upToN = [1..n]  // This is the list [1; 2; 3; ...; n]
    let add a b = a + b
    List.fold add 0 upToN

请注意,我写了List.fold 如果upToN是一个数组,那么我会编写Array.fold fold的参数,无论是List.fold还是Array.fold ,依次为:

  1. 执行计算的一个步骤的功能
  2. 计算的初始值
  3. 要使用的List.fold列表(如果使用List.fold )或数组(如果使用Array.fold )。

让我List.fold您完成List.fold工作。 我们会假装你已经调用4的功能价值n

第一步 :该列表是[1;2;3;4]和一个内部valueSoFar内部变量List.fold被设置为初始值,在我们的情况下是0。

下一步 :使用valueSoFar作为第一个参数调用计算函数(在我们的示例中为add ),并将列表的第一项作为第二个参数调用。 所以我们调用add 0 1并得到结果1.内部valueSoFar变量更新为1,列表的其余部分为[2;3;4] 由于尚未为空, List.fold将继续运行。

Next :调用计算函数( add ),将valueSoFar作为第一个参数,将列表其余部分的第一项作为第二个参数调用。 所以我们调用add 1 2并得到结果3.内部valueSoFar变量更新为3,列表的其余部分为[3;4] 由于尚未为空, List.fold将继续运行。

Next :调用计算函数( add ),将valueSoFar作为第一个参数,将列表其余部分的第一项作为第二个参数调用。 所以我们调用add 3 3并获得结果6.内部valueSoFar变量更新为6,列表的其余部分为[4] (这是一个包含一个项目的列表,数字4)。 由于尚未为空, List.fold将继续运行。

Next :调用计算函数( add ),将valueSoFar作为第一个参数,将列表其余部分的第一项作为第二个参数调用。 所以我们调用add 6 4并获得结果10.内部valueSoFar变量更新为10,列表的其余部分为[] (这是一个空列表)。 由于列表的其余部分现在为空, List.fold将停止,并返回valueSoFar的当前值作为其最终结果。

所以调用List.fold add 0 [1;2;3;4]将基本上返回0+1+2+3+4或10。

现在我们来谈谈scan scan函数就像fold函数一样,除了不返回最终值,它返回所有步骤(包括初始值)生成的值列表 (或者,如果您调用Array.scan ,它将返回在所有步骤中生成的值的数组)。 换句话说,如果你调用List.scan add 0 [1;2;3;4] ,它将执行与List.fold add 0 [1;2;3;4]相同的步骤List.fold add 0 [1;2;3;4] ,但它会建立一个结果列出计算的每一步,并返回[0;1;3;6;10] (初始值是列表的第一项,然后是计算的每一步)。

正如我所说,这些是高级功能,您的老师将不会覆盖它。 但我想我会对你能做什么感兴趣。 通过使用List.fold ,您不必编写while循环,或for循环,甚至使用递归:所有这些都是为您完成的! 您所要做的就是编写一个执行计算步骤的函数,F#将完成其余所有操作。

这是一个糟糕的主意:

let  mutable n = 7
let sumfunc2 (n: int byref)  =
    let mutable s = 0
    while n >=  1 do
        s <- n + (n - 1)
        n <- n-1
        printfn "%i" s

sumfunc2 (&n)

完全赞同munn的评论,这是另一种内爆方式:

let sumfunc3 (n: int)  =
    let mutable s = n
    while s >=  1 do
        let n =  s + (s - 1)
        s  <- (s-1)
        printfn "%i" n

sumfunc3 7

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM