本文章是由機器翻譯。

資料點

資料,滿足我的新朋友,F #

Julie Lerman

下載代碼示例

Julie Lerman函數式程式設計過去幾年一些暴露了這是隱式:編碼與LINQlambda 是函數式程式設計。一些已明確:使用LINQto SQL CompiledQuery 型和Entity Framework強迫我使用.NET Func 委託。那是總是有點棘手,因為我做的很少。我也受過到函數式程式設計通過傳染病的瑞吉兒 · 裡斯,微軟最有價值球員,不僅參加了我的本地使用者組 (VTdotNET),而且還在佛蒙特州,側重于許多方面和函數式程式設計語言中運行 VTFun 集團在這裡的人熱情。第一次去了 VTFun 次會議上,它充滿了數學家和火箭科學家。我不在開玩笑。常客之一就是在佛蒙特大學凝聚的態物理理論家。令人陶醉 !我是有點目不暇接的高級別討論,但很有趣,其實感覺像假人在房間裡。什麼說的最右翻我的頭 — 除了單個語句的引起我的注意:"函數式語言不需要無臭的 foreach 迴圈。哇 !我想要知道什麼意思。他們為什麼不需要的 foreach 迴圈?

我通常聽說是由於功能程式設計是偉大的數學運算。我不是個數學迷,解釋,以"為使用斐波那契序列測試出來的非同步行為的演示"的意思是並不支付更多的關注。這是只是一個短電梯攤位聽到函數式程式設計的問題。

但我終於開始聽到更準確的表徵 — 函數式程式設計是偉大的科學資料。那當然呼籲資料科學怪人。F #,功能的 Microsoft.NET 框架中,語言為.NET 開發人員帶來各種各樣的資料科學能力。它有整個圖書館致力於圖表、 時間操作和設置操作。它有 Api 與致力於 2D、 3D 和 4 D 陣列的邏輯。它理解的度量單位,能夠約束和驗證基於指定的單位。

F # 還允許Visual Studio中有趣的編碼方案。建立您的代碼檔中的邏輯,然後調試,你可以寫在互動式視窗中執行的程式碼的行,然後將成功代碼移到一個類檔。您可以獲得一種偉大的感覺 F # 作為一種語言與湯瑪斯 · 佩特日切克的文章,"認識世界與 F #"(bit.ly/1cx3cGx)。加入 F #.NET 工具集,由Visual Studio成為構建執行資料科學邏輯的應用程式的強大工具。

在這篇文章,我會重點在 F # 和我來理解以來聽到的評論不需要的 foreach 迴圈的函數程式設計的一個方面。功能性語言是很擅長處理的資料集。在程式語言中,當你工作集,與你有顯式逐一查看他們執行邏輯。函數式語言中,相比之下,理解上不同的級別,集,所以你只需要問問它要對一組,執行一個函數,而不是通過一套迴圈,並在每個專案上執行一個函數。可以有很多的邏輯,包括數學,如果有必要定義該函數。

LINQ提供了這一點,甚至可以將一個函數傳遞到其中一個 ForEach 方法的快捷方式。但在後臺,您的語言 (或許 C# 或Visual Basic) 只需將轉化為這一個迴圈。

如 F # 函數式語言已經執行 set 的函數在一個較低的水準,和它的更快由於其簡單的並行處理的能力。將添加到此其他關鍵好處,如豐富的數學處理能力和令人難以置信詳細的打字系統,甚至都不了解的度量,單位和你有一個強大的工具用於在大型資料集上執行計算。

有更多的 F # 和其他功能的語言,仍遠遠超出我到達的。但我想要在此列中是專注于一種方法快速受益的函數式語言的一個特定方面沒有作出了巨大的投資:將從資料庫的邏輯移到我的應用程式。這是我喜歡的學習的方式:找到幾個東西我可以理解並使用它們來考慮一些嬰兒學步到一個新的平臺、 語言、 框架或其他類型的工具。

我聽說裡斯試著弄清楚,開發人員使用的 F # 並不意味著發展語言切換。在同一方式您可能使用LINQ查詢或存儲的過程來解決具體的問題,您可以創建一個庫 F # 的方法來解決的各種問題在您的應用程式功能的語言是很擅長。

我將著重提取業務邏輯,內置到了我的資料庫,用於處理大型資料集的邏輯 — 東西在資料庫是優秀 — 並將它替換功能的方法。

並且因為 F # 旨在與集一起工作,是真的聰明與數學函數,代碼可以比它可能會在 SQL 中或在程式語言如 C# 或Visual Basic的更有效。它是那麼容易有 F # 中平行設置的專案上執行邏輯。這不僅可以減少您可能會需要的代碼量在程式語言中來類比這種行為,並行化意味著代碼將執行得更快。您可以設計 C# 代碼以並行運行,但我寧願不去通過這種努力,要麼。

真實世界的問題

許多年前,我寫了一個Visual Basic5 應用程式,必須收集、 維護和報告了很多科學資料和執行大量的運算。這些計算的一些如此複雜送給一個 Excel API。

計算之一涉及確定磅每平方英寸 (PSI) 基於造成材料打破一大塊的重量的量。大塊可能是任何一個數目的圓柱形狀和大小。應用程式將使用測量的油缸,並根據它的形狀和尺寸,具體的計算公式來計算其面積。它然後將適用有關公差因數和最後,重量的量才打破油缸。所有這一切在一起為正在測試的特定材料提供防擴散安全倡議。

1997 年,利用 Excel API 來計算公式從Visual Basic5 和Visual Basic6 內的覺得自己像一個漂亮聰明的辦法。

移動 Eval

年後,我改進了在.NET 中的應用。那時候,我決定利用SQL Server的電源之後他們更新了一個使用者,而不是在使用者的電腦上所有這些計算的花時間, 在大集上的氣瓶執行防擴散安全倡議計算。這出得很好。

更多年過去了,我對資料庫中的業務邏輯的理念改變了。我想要拉回用戶端的計算,當然,用戶端機器快到那時,反正。這不是太難了,重寫在 C# 中的邏輯。更新使用者花了才打破它們 (負荷、 代表在磅) 的重量與一系列的氣瓶後,應用程式將逐一查看更新後的氣瓶和計算 PSI。然後我可以與他們新的裝載和 PSI 值更新資料庫中的氣瓶。

為了比較熟悉 C# F # (,你很快就會看到) 中的最終結果,我提供了上市的缸類型,CylinderMeasurements,在圖 1 和我計算機 C# 類中的圖 2,因此,你可以看到我如何獲得一組氣瓶催。它是 CylinderCalculator.UpdateCylinders 方法被調用來啟動防擴散安全倡議計算為一組的氣瓶。它將逐一查看集合中的每個氣缸,並執行適當的計算。請注意一種方法,GetAreaForCalculation,取決於缸類型因為我使用的適當公式圓柱的面積計算。

圖 1 CylinderMeasurement 類

public class CylinderMeasurement
{
  public CylinderMeasurement(double widthA, double widthB,
    double height)
  {
    WidthA = widthA;
    WidthB = widthB;
    Height = height;
  }
  public int Id { get; private set; }
  public double Height { get; private set; }
  public double WidthB { get; private set; }
  public double WidthA { get; private set; }
  public int LoadPounds { get; private set; }
  public double Psi { get; set; }
  public CylinderType CylinderType { get; set; }
  public void UpdateLoadPoundsAndTypeEnum(int load, 
    CylinderType cylType) {
    LoadPounds = load; CylinderType = cylType;
  }
   private double?
Ratio {
    get {
      if (Height > 0 && WidthA + WidthB > 0) {
        return Math.Round(Height / ((WidthA + WidthB) / 2), 2);
      }
      return null;
    }
  }
  public double ToleranceFactor {
    get {
      if (Ratio > 1.94 || Ratio < 1) {
        return 1;
      }
      return .979;
    }
  }
}

圖 2 計算機類來計算防擴散安全倡議

public static class CylinderCalculator
  {
    private static CylinderMeasurement _currentCyl;
    public static void UpdateCylinders(IEnumerable<CylinderMeasurement> cyls) {
      foreach (var cyl in cyls)
      {
        _currentCyl = cyl;
        cyl.Psi = GetPsi();
      }
    }
    private static double GetPsi() {
      var area = GetAreaForCylinder();
      return PsiCalculator(area);
    }
    private static double GetAreaForCylinder() {
      switch (_currentCyl.CylinderType)
      {
        case CylinderType.FourFourEightCylinder:
          return 3.14159*((_currentCyl.WidthA + _currentCyl.WidthB)/2)/2*
            ((_currentCyl.WidthA + _currentCyl.WidthB)/2/2);
        case CylinderType.SixSixTwelveCylinder:
          return 3.14159*((_currentCyl.WidthA + _currentCyl.WidthB)/2)/2*
            ((_currentCyl.WidthA + _currentCyl.WidthB)/2/2);
        case CylinderType.ThreeThreeSixCylinder:
          return _currentCyl.WidthA*_currentCyl.WidthB;
        case CylinderType.TwoTwoTwoCylinder:
          return ((_currentCyl.WidthA + _currentCyl.WidthB)/2)*
            ((_currentCyl.WidthA + _currentCyl.WidthB)/2);
        default:
          throw new ArgumentOutOfRangeException();
      }
    }
    private static int PsiCalculator(double area) {
      if (_currentCyl.LoadPounds > 0 && area > 0)
      {
        return (int) (Math.Round(_currentCyl.LoadPounds/area/1000*
          _currentCyl.ToleranceFactor, 2)*1000);
      }
      return 0;
    }
  }

資料重點和更快的處理與 F #

最後,我發現 F # 中,由於其自然傾向用於操作的資料,提供了更好的解決方案比一次評價一個公式。

在介紹性會議上 F # 的裡斯,我解釋過這個問題,一直嘮叨著我那麼多年,又問如果可以使用功能性語言更令人滿意的方式解決它。 她證實可以應用我完成計算邏輯上一套完整,讓 F # 派生很多缸並聯催。 我可以在同一時間獲取用戶端的功能和性能提升。

對我來說關鍵是要意識到我可以使用 F # 解決具體的問題在很多相同的方式使用存儲的過程 — 它是在我工具帶的另一種工具。 它不需要放棄我在 C# 中的投資。 也許有一些人是正好相反 — 在 F # 中編寫自己的應用程式的大容量和使用 C# 來攻擊特別的問題。 在任何情況下,使用 C# CylinderCalculator 作為一個指南,裡斯創建了一個小 F # 專案的任務和我是能夠對我的計算機的調用替換調用到她在我的測試中,如中所示圖 3

圖 3 F # PSI 計算機

module calcPsi =
  let fourFourEightFormula WA WB = 3.14159*((WA+WB)/2.)/2.*((WA+WB)/2./2.)
  let sixSixTwelveFormula WA WB = 3.14159*((WA+WB)/2.)/2.*((WA+WB)/2./2.)
  let threeThreeSixFormula (WA:float) (WB:float) = WA*WB
  let twoTwoTwoFormula WA WB = ((WA+WB)/2.)*((WA+WB)/2.)
  // Ratio function
  let ratioFormula height widthA widthB =
    if (height > 0.
&& (widthA + widthB > 0.)) then
      Some(Math.Round(height / ((widthA + widthB)/2.), 2))
    else
      None
  // Tolerance function
  let tolerance (ratioValue:float option) = match ratioValue with
    | _ when (ratioValue.IsSome && ratioValue.Value > 1.94) -> 1.
| _ when (ratioValue.IsSome && ratioValue.Value < 1.) -> 1.
| _ -> 0.979
  // Update the PSI, and return the original cylinder information.
let calculatePsi (cyl:CylinderMeasurement) =
    let formula = match cyl.CylinderType with
      | CylinderType.FourFourEightCylinder -> fourFourEightFormula
      | CylinderType.SixSixTwelveCylinder -> sixSixTwelveFormula
      | CylinderType.ThreeThreeSixCylinder -> threeThreeSixFormula
      | CylinderType.TwoTwoTwoCylinder -> twoTwoTwoFormula
      | _ -> failwith "Unknown cylinder"
    let basearea = formula cyl.WidthA cyl.WidthB
    let ratio = ratioFormula cyl.Height cylinder.WidthA cyl.WidthB
    let tFactor = tolerance ratio
    let PSI = Math.Round((float)cyl.LoadPounds/basearea/1000.
* tFactor, 2)*1000.
cyl.Psi <- PSI
    cyl
  // Map evaluate to handle all given cylinders.
let getPsi (cylinders:CylinderMeasurement[])
              = Array.Parallel.map calculatePsi cylinders

如果像我一樣,你是新到 F # 中,你可能只看代碼的數量,看沒有選擇這條路線,而不是 C# 中的點。 然而,仔細研究後您可能喜歡精練的語言,定義公式更優雅,並在結束時,我可以申請 · 裡斯向我傳遞給該方法的圓筒的陣列定義的 calculatePsi 函數的簡單方法的能力。

簡潔性是由於這一事實 F # 更好地設計,以便執行數學函數比 C#,所以定義這些函數是效率更高。 但除了語言的怪人上訴,我感興趣的性能。 當我在我的測試中增加了每套圓筒的數量時,最初我不看性能的改善超過 C#。 裡斯解釋時使用的 F # 是更昂貴的測試環境。 所以我然後測試性能在使用碼錶來報告時間通過一個主控台應用程式中。 這款應用程式建立起來的 50,000 氣瓶的清單,啟動碼錶,傳遞到 C# 或 F # 計算機來更新的 PSI 值為每個圓筒,圓筒然後計算都已完成時,停止碼錶。

在大多數情況下,C# 過程大約 3 倍比長 F # 過程中,雖然會比約 20%的時間 C# F # 小幅度。 我不能佔有點奇怪,但它是可能還有更多我需要瞭解要執行更真實的性能分析。

保持警惕的邏輯乞求的功能語言

所以我要在我的 F # 技能工作,但我新的理解要很好地適用于已經在生產中的應用程式,以及將來的應用程式。 在我生產的應用程式,我可以看看我已經退居到資料庫,並考慮是否一個應用程式將受益于 F # 更換的業務邏輯。 與新的應用程式,現在更熱衷眼的檢舉功能,我可以更有效地編碼與 F # 中,執行資料操作,利用強型別的測量單位和獲得的性能。 總是有學習新的語言及尋找只是它建成的正確方案的樂趣 !

Julie Lerman 是微軟最有價值球員,.NET 的導師和諮詢師,住在佛蒙特州的山裡。你可以找到她提出關於資料訪問和使用者組和會議,世界各地其他 Microsoft.NET 主題。在她博客 thedatafarm.com/blog 和的作者是"程式設計Entity Framework"(2010 年) 以及代碼第一版 (2011 年) 和 DbCoNtext 版 (2012 年),所有從 O'Reilly 媒體。跟著她在 Twitter 上 twitter.com/julielerman 看看她的 Pluralsight 課程 juliel.me/PS-視頻

由於以下的技術專家對本文的審閱:瑞吉兒 · 裡斯 (螢火蟲邏輯)
瑞吉兒 · 裡斯是一個長期的軟體工程師和數學怪人在納什維爾,tn 表示的元件 直到最近,她跑了伯靈頓,VT 功能程式設計使用者組 @VTFun,這是一個恒定的她,並在其中她常常談到 F # 的靈感來源。 她也是 ASPInsider、 F # 最有價值球員、 社區愛好者,成立一個 @lambdaladies,和 Rachii。 你可以找到她在 twitter 上, @rachelreese,或在她的博客上:rachelree.se