2010-07-07 23 views
7

這裏的代碼工作正常:F#中可能會使用中間函數參數嗎?

let f x y z = x + y + z 

let g x y = f x y 
let h x z = z |> f x 

所以,我可以寫表達 「H 1」 和FSI顯示:

val it : (int -> int -> int) = <fun:[email protected]> 

如果我稱之爲 「H 1 2 3」,參數應用按照正確的順序。
但如果最後一個參數有不同的類型,事情變得不同:

let ff x y (z : string) = x + y 

let gg x y = ff x y 
let hh x (z : string) = z |> ff x 

現在最後一個函數HH導致一個錯誤信息:

Script.fsx(119,10):錯誤FS0001 : 類型不匹配。期待string -> 'a 但給出int -> string -> int。該類型string不匹配的類型int

我明白爲什麼會這樣 - 「Z」附加到「FF X」使其成爲第二個參數。但後來我想在第一個例子中表達式「h 1 2 3」不能正常工作(被執行爲「f 1 3 2」)。但它工作得很好。

+1

你確定'h 1 2 3'執行爲'f 1 2 3'而不是'f 1 3 2'嗎?畢竟,1 + 2 + 3 == 1 + 3 + 2 == 6.也許嘗試與非傳遞算子? – tzaman 2010-07-07 13:11:27

+0

FWIW,OCaml標註的參數允許您部分無序應用。 – 2010-07-08 23:28:46

回答

8

在您的示例中,函數ffgg是相同的 - 流水線運算符爲右側函數的第一個參數提供值。在你的榜樣,在右側的功能是ff x,通過使用流水線操作,你的說法y指定的值:

let ff x y (z : string) = 
    printfn "%s" z 
    x + y 

// These two functions are the same: 
let gg x y = ff x y 
let hh x y = y |> ff x 

沒有爲使用部分功能時比第一參數指定其他沒有stnadard語法應用。但是,您可以編寫更高級的函數或自定義運算符來完成此操作。例如:

// Takes a function 'f' of type 'b -> 'a -> 'c 
// and a value 'v' of type 'a and creates a function 
// that takes the first argument ('b -> 'c) 
let (|*>) v f = (fun mid -> f mid v);; 

let gg x y = ff x y  // Specifies arguments x and y 
let hh x z = z |*> ff x // Specifies arguments x and z 

我命名操作|*>表示,它跳過一個參數。您可以定義類似地指定其他參數值的運算符(例如|**>跳過前兩個參數)。

+0

托馬斯,謝謝你的答案。自定義運算符的使用似乎是一種方式! – 2010-07-07 14:38:47

+1

我認爲你在那個操作符中擁有落後的論點。我認爲這應該是(最後的樂趣 - >最後)。另外,函數應用優先於運算符,因此最後一行應該是:(z | *> ff)x 嘗試使用減法或除法來測試它,而不是加法。 – YotaXP 2010-07-07 16:10:42

+0

@YotaXP:你提到的兩件事都是故意的。如果你按照你描述的方式編寫操作符(例如'last last - > fv last'),那麼你根本不需要lambda函數,因爲這相當於'fv' - 這將是標準的'|>'操作符。 關於第二點 - 意圖是當你寫'z | *> ff x'時,你指定'z'作爲函數ff x的第二個參數(並且第一個參數有待指定)。換句話說,'z | *> ff x'相當於'fun a - > ff x a z'。 – 2010-07-07 16:47:27

相關問題