比方說,我有一個列表和一組,我想要做的一些東西與他們:F#:在地圖殺死冗餘/縮小/濾波器
let outA = inA |> List.map(fun x -> x + 1) |> List.filter(fun x -> x > 10)
let outB = inB |> Set.map(fun x -> x + 1) |> Set.filter(fun x -> x > 10)
現在,顯然是處理名單和B處理組。然而,我覺得非常煩人的是不得不一遍又一遍地寫List.
List.
:它不僅是冗長的,重複的樣板,它沒有傳達任何信息,並妨礙了閱讀代碼的功能,它也是事實上的類型註釋,我必須跟蹤並與代碼的其餘部分保持同步。
我希望能夠做的是類似如下:
let outA = inA |> map(fun x -> x + 1) |> filter(fun x -> x > 10)
let outB = inB |> map(fun x -> x + 1) |> filter(fun x -> x > 10)
隨着編譯器知道INA是列表,INB是一組,因此,所有的操作都是從正確的類,因此outA是一個列表,outB是一個集合。我可以通過Seq部分實現這一點:
let map(x) =
Seq.map(x)
let filter(x) =
Seq.filter(x)
而且我可以寫得完全一樣。問題在於它將所有內容都轉換爲序列,並且我不能再對它們執行列表/設置操作。同樣,
let outA = inA.Select(fun x -> x + 1).Where(fun x -> x > 10)
let outB = inB.Select(fun x -> x + 1).Where(fun x -> x > 10)
也刪除所有,但然後將所有東西都轉換爲IEnumerable。我設法得到它相當不錯的擴展通過將所有的靜態方法爲實例方法:
type Microsoft.FSharp.Collections.List<'a> with
member this.map(f) = this |> List.map(f)
member this.filter(f) = this |> List.filter(f)
let b = a.map(fun x -> x + 1).filter(fun x -> x > 10)
但我懷疑這會碰上這裏所提到的類型推斷的問題:Method Chaining vs |> Pipe Operator?我真的不知道;我不熟悉類型推斷算法的工作原理。
底線是,我想我會做很多這些列表/設置/數組映射/減少/過濾操作,我想讓他們看起來儘可能漂亮和乾淨。現在,除了分散我在表達式中的重要位置(即「map」和lambda)外,他們還提供了事實上的類型註釋,在編譯器應該快速的地方 - 很好地知道我的集合是什麼傳入是。此外,這正是OO繼承和多態性意味着要解決的事情,所以我想知道是否有一些等價的功能模式,我不知道它會像優雅地解決它。也許我可以在我自己的靜態map
中進行類型檢查,並在輸入上執行相關類型的map
函數?
有沒有人比我已經嘗試過的更好的解決方案,還是我碰到F#類型推理引擎的根本限制,我應該接受並繼續前進?
在我看來,在模塊名稱使代碼更具描述性。通過查看代碼,您知道它是一個List/Set。 – ebb
基本上你想要type-classes :)結帳Haskell,或者留在我們這裏並使用合格的名字。 –
@ebb:但是類型推理的觀點是,我不需要描述這麼多的代碼= D。 –