[英]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.