2011-03-26 53 views
9

我明白在F#功能組合物的基礎,如,例如,描述here我錯過了什麼:函數組合可能有多個參數?

也許我失去了一些東西,但。該>><<運營商似乎已經與假設定義的每個函數只需要一個參數:

> (>>);; 
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:[email protected]> 
> (<<);; 
val it : (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b) = <fun:[email protected]> 

我今天準備這樣做,但是,類似如下:

let add a b = a + b 
let double c = 2*c 
let addAndDouble = add >> double // bad! 

但是,即使add的輸出是double的輸入所需的類型,但它被拒絕。

我知道我可以重寫添加一個元組的參數:

let add (a,b) = a + b 

或者,我可以寫的可能的參數每隔數到第一功能的新的運營商:

let inline (>>+) f g x y = g (f x y) 
let doubleAdd = add >>+ double 

但看起來很傻!有沒有更好的方式,我錯過了?

回答

11

你想要的並不完全不合理,但是沒有辦法指出F#類型中的泛化合成運算符的類型系統。也就是說,有統一

(>>) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c 

(>>+) : ('a -> 'b -> 'c) -> ('c -> 'd) -> 'a -> 'b -> 'd 

(更不用說無限多的元數較高版本),沒有什麼好辦法。因此,你別無選擇,只能定義你自己的附加操作符。在實踐中,我經常發現寫在「尖」的風格let f x y = add x y |> double比/自由點「毫無意義」 let f = add (>>+) double反正更可讀的代碼。

+1

同意的,尖銳的風格往往是更具可讀性。 – Laurent 2011-03-27 01:32:38

+2

特別是當你開始不得不「翻轉」你的功能。 – 2011-03-27 07:00:37

4

看那類型的>><<您在上面發佈。例如:

> (>>);; 
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:[email protected]> 

它有兩個功能,一個值('a),返回另一個值。你需要一些需要兩個函數和兩個值的東西。因此,>><<都沒有正確的類型簽名。

你的實現是不是傻的。這只是您的要求不會在F#的圖書館中出現。要感謝你有一種語言,它允許你定義你自己的運營商,像這樣:)

3

如何通過線程的參數堆棧?

let add = function x :: y :: t -> x + y :: t 
let double = function x :: t -> 2 * x :: t 

然後你就可以撰寫的任意元數的功能:

let doubleAdd = add >> double 

而且它的工作原理:

> doubleAdd [7; 14] 
42 

(見F# Function Composition with multiple input parameters

相關問題