[英]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建议我告诉你如何使用fold
和scan
功能,我想“为什么不呢?” 请记住,这些都是高级技术,因此您可能无法在需要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
,依次为:
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.