簡體   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