簡體   English   中英

為什么輸出是 <seq> 而不是int in F#?

[英]Why output is <seq> and not int in F#?

這是我的代碼:

 Csv.GetSample().Rows
 |> Seq.groupBy (fun row -> row.STATE,row.INCOME,row.CHILDREN)
 |> Seq.map (fun ((state,income,children),data) -> 
    let pctrepub = data|> Seq.map (fun row -> (100.0 - float row.otherparty)) 
    ((state,income,children),pctrepub))
 |> List.ofSeq

這是我理想的結果:

   (("TX", "51522", "0"), 65.0);
   (("AL", "6481", "1"), 51.4);
   (("MO", "78921", "1"), 25.1);
   (("TN", "12000", "4"), 62.1);
   (("PA", "79850", "2"), 41.2);
   (("NY", "79215", "1"), 31.0);
   (("CA", "79045", "2"), 50.5);

這就是我最終得到的結果:

   (("TX", "51522", "0"), <seq>);
   (("AL", "6481", "1"), <seq>);
   (("MO", "78921", "1"), <seq>);
   (("TN", "12000", "4"), <seq>);
   (("PA", "79850", "2"), <seq>);
   (("NY", "79215", "1"), <seq>);
   (("CA", "79045", "2"), <seq>);

為什么最后一行值顯示為<seq> ,我該如何解決?

元組的最后一個元素是pctrepub ,這是Seq.map調用的結果,並且Seq.map返回一個序列,而不是數字。 因此,元組的最后一個元素是序列絕對不奇怪。

關於如何解決此問題,沒有足夠的信息:我看到您想獲取數字而不是序列,但是您並不是在說數字應該從哪里來,所以我無法為您提供幫助。

您在其他地方提到過,您是F#的初學者(八天前開始學習它),因此,這是如何閱讀F#文檔的快速指南,它可以幫助您自己回答其中的一些問題。 讓我們看一下Seq模塊文檔 它列出了許多可以在序列上調用的函數: appendaverageaverageByfiltermapgroupBy …它們都有不同的類型簽名,每個函數的類型簽名都是其作用的線索。 讓我們看幾個例子:

  • averageseq<^T> -> ^T返回序列中元素的平均值。
  • averageBy :( ('T -> ^U) -> seq<'T> -> ^U返回通過將函數應用於序列的每個元素而生成的結果的平均值。
  • map :( ('T -> 'U) -> seq<'T> -> seq<'U> -創建一個新集合,其元素是將給定功能應用於集合的每個元素的結果。

首先, average ,因為它是最簡單的。 類型標記中的->箭頭告訴您這是一個函數。 輸入在箭頭的左邊,輸出在箭頭的右邊。 因此,該類型簽名意味着此函數采用seq<^T>並返回^T類型的項。 類型名稱T前面的^'字符表示它是通用類型,它將在運行代碼時解析為您實際擁有的任何類型:int,字符串,元組等。 因此, T只是您實際擁有的任何類型的占位符名稱:如果您有int,則這是seq<int> -> int函數。 如果您有字符串,這是seq<string> -> string函數,依此類推。 (類型前面的^字符表示將在編譯時進行解析,而類型前面的'字符表示將在運行時進行解析。在您完成此操作之前,無需擔心這種區別。在F#方面有更多的經驗,所以現在,只需將其中一個當作標志,就意味着“這是一個通用類型”)。 因此, average函數的類型簽名告訴您,它采用一系列值並返回一個值

現在, averageBy 這更加復雜。 首先,這里還有更多箭頭。 這與一個名為currying的概念有關,在鏈接上對此解釋得很好,因此我不會深入探討。 在初學者級別,您應該將最后一個箭頭之后的內容視為函數的輸出,並將所有其他類型視為函數的輸入(將由箭頭分隔)。 換句話說,類型簽名(例如int -> char -> string應被理解為“這是一個需要兩個輸入的函數,首先輸入int ,然后輸入char ,然后返回string 。”

但是,您是否在averageBy類型簽名中的('T -> ^U)位周圍看到括號? 這些括號的含義與數學含義相同:請單獨閱讀本部分。 因此, averageBy的第一個參數是類型('T -> ^U) averageBy的第二個參數的類型為seq<'T> ,輸出的類型為^U 現在,如果您查看類型簽名('T -> ^U) ,它上面有一個箭頭,因此它是一個函數。 具體來說,它是一個函數,它接受通用類型T的東西,並返回通用類型U的東西。 (正如我之前說的,現在不必擔心' vs. ^區別)。 第二個參數是T類型的項目序列,輸出是U類型。 該類型簽名加上名稱,為您提供有關函數工作方式的線索:它將查看類型T的事物序列,對於每個事物,它將調用該函數將T事物轉換為事物。輸入U 然后,它返回一個U值作為輸出:從名稱中可以得出結論,它返回的單個值將是'T -> ^U函數產生的所有U值的平均值。

因此,類型簽名('T -> ^U) -> seq<'T> -> ^U表示第一個參數是一個接受T並返回U的函數,第二個參數是一個類型為null的項目序列T ,並且該函數返回單個類型U項目。

最后,讓我們看一下map 它的類型簽名看起來與averageBy非常相似:第一個參數還是一個接受T並將其轉換為U的函數。 第二個參數還是T項的序列。 但是這次, map的結果將是一系列 U值,而不是單個值。

因此,通過查看文檔 ,我們可以看到,如果您不希望將序列作為輸出,則調用Seq.map是錯誤的事情。 Seq模塊中的函數列表令人迷惑,因此您可能會覺得不知所措。 但是仔細查看類型簽名,並理解每個簽名的含義,對於確定哪個簽名可以滿足您的數據需求將大有幫助。 並且通讀https://fsharpforfunandprofit.com/posts/list-module-functions/對您也有很大幫助:F#將ListSeqArray模塊視為彼此極其相似 ,包括幾乎所有相同的功能。 因此,如果您知道List.averageBy功能,那么您還將知道Seq.averageByArray.averageBy功能:唯一的區別在於它們將哪種類型的集合用作輸入。 因此,即使該頁面討論列表,它的建議也適用於Seq。

有人已經在評論中回答了您的問題(只需執行Seq.map (fun row -> (row.STATE,row.INCOME,row.CHILDREN), 100.0 - float row.otherparty) ,您就應該得到想要的結果) ,因此我在這里不再贅述。 希望我花時間寫這篇文章將對您有所幫助,以幫助您更深入地理解事物,以便您將來可以回答自己的問題,而不必太依賴於對Stack Overflow的詢問(和然后等待,有時需要幾個小時才能找到答案)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM