任何人都有一個體面的例子,最好實用/有用,他們可以發佈展示的概念?F#curried功能
回答
(編輯:小Ocaml FP Koan開始做事了)
柯里的公案(約食物公案,即不是食品)
學生來到對雅克·加里古說:「我不明白什麼咖喱是好的。」雅克回答說,「告訴我你最喜歡的餐點和你最喜歡的甜點」。這位疑惑的學生回答說,他喜歡大阪燒和卡寧,但是當他最喜歡的餐廳供應很棒的大阪燒時,他們的筷子總是在第二天早上給他肚子疼。所以雅克帶着學生在一家餐廳裏吃了大阪燒,然後把他帶到了一家商店,那家餐館做得非常出色,在那裏學生們愉快地運用了剩下的食慾。這個學生是坐着的,但他沒有開悟......直到第二天早上他醒來時,他的肚子感覺很好。
我的例子將介紹如何使用它的重用和代碼封裝。一旦你看到這些,這是相當明顯的,並且應該給你一個具體的,簡單的例子,你可以考慮在許多情況下應用。
我們想要在樹上做一個地圖。如果需要多於一個參數的話,這個函數可以被curry應用到每個節點上 - 因爲我們會在節點上應用這個函數作爲最終的參數。它不需要被搞熟,但是編寫另一個函數(假設這個函數在其他變量的其他實例中被使用)將是浪費。
type 'a tree = E of 'a | N of 'a * 'a tree * 'a tree
let rec tree_map f tree = match tree with
| N(x,left,right) -> N(f x, tree_map f left, tree_map f right)
| E(x) -> E(f x)
let sample_tree = N(1,E(3),E(4)
let multiply x y = x * y
let sample_tree2 = tree_map (multiply 3) sample_tree
但這是一樣的:
let sample_tree2 = tree_map (fun x -> x * 3) sample_tree
所以這種簡單的情況下是不能令人信服的。當你更多地使用這種語言並自然地遇到這些情況時,它確實是非常強大的。另一個例子是將一些代碼重用爲currying。 A recurrence relation to create prime numbers。非常多的相似性在裏面:
let rec f_recurrence f a seed n =
match n with
| a -> seed
| _ -> let prev = f_recurrence f a seed (n-1) in
prev + (f n prev)
let rowland = f_recurrence gcd 1 7
let cloitre = f_recurrence lcm 1 1
let rowland_prime n = (rowland (n+1)) - (rowland n)
let cloitre_prime n = ((cloitre (n+1))/(cloitre n)) - 1
好了,現在羅蘭和cloitre是咖喱的功能,因爲他們有自由變量,我們可以得到任何指標是不知道或擔心f_recurrence序列。
這是一個相當簡單的過程。拿一個函數,綁定它的一個參數並返回一個新的函數。例如:
let concatStrings left right = left + right
let makeCommandPrompt= appendString "c:\> "
現在,通過討好簡單concatStrings功能,您可以輕鬆地添加一個DOS風格的命令提示符下,以任何字符串的面前!真的有用!
好的,不是真的。我發現一個更有用的情況是,當我想讓一個函數返回像流一樣的數據流。
let readDWORD array i = array[i] | array[i + 1] << 8 | array[i + 2] << 16 |
array[i + 3] << 24 //I've actually used this function in Python.
關於它的方便的是,而不是爲這樣的事情一整類,調用構造函數,調用obj.readDWORD(),你就必須不能從突變出來的函數在你下面。
這個答案描述了部分函數應用[它與currying有關,但不是同一件事](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application) – phoog 2013-02-09 04:30:37
雖然前面的例子回答了這個問題,但下面是兩個簡單的例子,說明Currying如何對F#編程有利。
open System.IO
let appendFile (fileName : string) (text : string) =
let file = new StreamWriter(fileName, true)
file.WriteLine(text)
file.Close()
// Call it normally
appendFile @"D:\Log.txt" "Processing Event X..."
// If you curry the function, you don't need to keep specifying the
// log file name.
let curriedAppendFile = appendFile @"D:\Log.txt"
// Adds data to "Log.txt"
curriedAppendFile "Processing Event Y..."
不要忘了你可以咖喱Printf家族的功能!在咖喱版中,請注意明顯缺乏lambda。
// Non curried, Prints 1 2 3
List.iter (fun i -> printf "%d " i) [1 .. 3];;
// Curried, Prints 1 2 3
List.iter (printfn "%d ") [1 .. 3];;
這個答案描述了部分函數的應用,[這與currying有關,但不是相同的東西]( http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application) – phoog 2013-02-09 04:30:04
你知道你可以將函數映射到列表上嗎?例如,映射函數來添加一個到列表中的每個元素:
> List.map ((+) 1) [1; 2; 3];;
val it : int list = [2; 3; 4]
這實際上已經在使用鑽營,因爲(+)
操作來創建一個函數來添加一個到它的參數,但你可以擠多一點這個示例中,通過改變它映射列出的名單相同的功能:
> List.map (List.map ((+) 1)) [[1; 2]; [3]];;
val it : int list = [[2; 3]; [4]]
不討好你不能部分地應用這些功能,會寫這樣的事情,而不是:
> List.map((fun xs -> List.map((fun n -> n + 1), xs)), [[1; 2]; [3]]);;
val it : int list = [[2; 3]; [4]]
這個答案描述了部分函數的應用,[這與currying有關,但不是相同的東西](http://en.wikipedia.org/wiki/柯里#Contrast_with_partial_function_application) – phoog 2013-02-09 04:30:53
@phoog這個答案正確的解析ains說:「不用捲曲你就不能部分應用這些功能」。 – 2013-02-09 08:58:40
我給了一個很好的模擬C#中的柯里化的例子#on my blog。要點是您可以創建一個函數,該函數在一個現有的多參數函數中通過一個參數關閉(在我的示例中,創建一個函數,用於計算關於給定自治市的價值的銷售稅關閉)。
這裏吸引人的地方在於,不必爲庫克縣計算銷售稅專門制定單獨的函數,您可以在運行時動態創建(並重新使用)函數。
+1,儘管您的博客鏈接似乎已被打破,但我懷疑您的示例顯示了C#中的實際功能,並未模擬。這個答案是唯一一個將currying描述爲啓用部分函數應用程序的東西,而不是將其與部分函數應用程序混淆。 – phoog 2013-02-09 04:33:56
Currying描述了將具有多個參數的函數轉換爲單參數函數鏈的過程。例如在C#中,對於三參數功能:現在
Func<T1, Func<T2, Func<T3, T4>>> Curry<T1, T2, T3, T4>(Func<T1, T2, T3, T4> f)
{
return a => b => c => f(a, b, c);
}
void UseACurriedFunction()
{
var curryCompare = Curry<string, string, bool, int>(String.Compare);
var a = "SomeString";
var b = "SOMESTRING";
Console.WriteLine(String.Compare(a, b, true));
Console.WriteLine(curryCompare(a)(b)(true));
//partial application
var compareAWithB = curryCompare(a)(b);
Console.WriteLine(compareAWithB(true));
Console.WriteLine(compareAWithB(false));
}
,boolean變量可能是不你最有可能要離開開放與部分應用程序的說法。這就是爲什麼F#函數中的參數順序起初看起來有點奇怪的原因之一。讓我們定義一個不同的C#咖喱功能:
Func<T3, Func<T2, Func<T1, T4>>> BackwardsCurry<T1, T2, T3, T4>(Func<T1, T2, T3, T4> f)
{
return a => b => c => f(c, b, a);
}
現在,我們可以做一些更有益的:
void UseADifferentlyCurriedFunction()
{
var curryCompare = BackwardsCurry<string, string, bool, int>(String.Compare);
var caseSensitiveCompare = curryCompare(false);
var caseInsensitiveCompare = curryCompare(true);
var format = Curry<string, string, string, string>(String.Format)("Results of comparing {0} with {1}:");
var strings = new[] {"Hello", "HELLO", "Greetings", "GREETINGS"};
foreach (var s in strings)
{
var caseSensitiveCompareWithS = caseSensitiveCompare(s);
var caseInsensitiveCompareWithS = caseInsensitiveCompare(s);
var formatWithS = format(s);
foreach (var t in strings)
{
Console.WriteLine(formatWithS(t));
Console.WriteLine(caseSensitiveCompareWithS(t));
Console.WriteLine(caseInsensitiveCompareWithS(t));
}
}
}
爲什麼在C#這些例子?因爲在F#中,函數聲明默認爲curried。你通常不需要咖喱功能;他們已經咖喱了。這個主要的例外是框架方法和其他重載函數,它們包含一個包含多個參數的元組。因此,你可能想要咀嚼這樣的功能,而事實上,當我正在尋找一個能夠做到這一點的庫函數時,我就會遇到這個問題。我想這是缺少(如果確實是),因爲它是很容易實現:
let curry f a b c = f(a, b, c)
//overload resolution failure: there are two overloads with three arguments.
//let curryCompare = curry String.Compare
//This one might be more useful; it works because there's only one 3-argument overload
let backCurry f a b c = f(c, b, a)
let intParse = backCurry Int32.Parse
let intParseCurrentCultureAnyStyle = intParse CultureInfo.CurrentCulture NumberStyles.Any
let myInt = intParseCurrentCultureAnyStyle "23"
let myOtherInt = intParseCurrentCultureAnyStyle "42"
要獲得String.Compare繞過故障,因爲據我可以告訴有沒有辦法來指定哪些3-參數超載來接,你可以使用一個非一般的解決方案:
let curryCompare s1 s2 (b:bool) = String.Compare(s1, s2, b)
let backwardsCurryCompare (b:bool) s1 s2 = String.Compare(s1, s2, b)
我不會去到有關部分功能應用在F#的使用細節,因爲其他的答案已經覆蓋了已經。
- 1. Curried函數f#
- 2. 獲得curried功能的效果
- 3. F#:curried過載/元組過載問題
- 4. F#功能界面
- 5. F#Ununit - reunit功能
- 6. F#功能VS C# 「功能」 蒸發散
- 7. F#朋友功能/類
- 8. 過濾功能少於+ F
- 9. 緩存功能結果f#
- 10. F#功能組成參數
- 11. F#:仍然不能爲通用功能
- 12. F#動態操作讓訪問既功能和功能名稱
- 13. Curried UDF - Pyspark
- 14. print_int和其他F#打印功能
- 15. F#不清楚功能的影響
- 16. 函數返回功能和F#
- 17. F#+網絡,使用System.Math.Floor功能
- 18. F#模式匹配和功能
- 19. F#(或.NET庫)的統計功能
- 20. F#2008中的自動完成功能
- 21. F#中列表中的切片功能#
- 22. 製作按Ctrl-F功能用於wx.TextCtrl
- 23. F#:存儲和映射功能列表
- 24. F#撰寫模式匹配功能
- 25. 基於輸入的F#Pick功能?
- 26. 用`尾-f`功能日誌存儲
- 27. 部分功能的F#異常處理
- 28. 如何使用AS3的功能類型(VAR F:功能)的方法F(S:字符串)
- 29. 如何動態更改功能界面,例如F() - > F(A,B,C =「默認」)
- 30. Scala:foreach中的curried函數?
這個答案描述了部分函數應用,[which (http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application) – phoog 2013-02-09 04:29:17