2017-01-05 102 views
3

使用序列我的價值序列,我想申請到部分功能:上部分應用程序

let f a b c d e= a+b+c+d+e 

let items = [1,2,3,4,5] 

let result = applyPartially f items 

Assert.Equal(15, result) 

我的applyPartially功能之後尋找。我曾嘗試寫這樣的遞歸函數:

let rec applyPartially f items = 
| [] -> f 
| [x] -> f x 
| head :: tail -> applyPartially (f head) tail 

我所遇到的問題是,F型是在我的迭代「A - >」的開始乙 - >「C - >」 D->」 e,並且對於每個循環它都應該消費一個訂單。

'a->'b->'c->'d->'e 
'b->'c->'d->'e 
'c->'d->'e 
'd->'e 

這意味着我能想到的下界面是'd - >'e。我怎麼能隱藏我的函數的複雜性,以便在遞歸函數中只顯示'd - >'e?

回答

5

F#類型的系統沒有一種用你建議的方式處理普通函數的好方法 - 爲此,你需要確保列表的長度與參數的數量匹配函數,這對普通的列表和函數是不可能的。

但是,您可以使用區分聯合對此進行很好的建模。您可以定義的部分功能,這已完成,或者需要多一個輸入:

type PartialFunction<'T, 'R> = 
    | Completed of 'R 
    | NeedsMore of ('T -> PartialFunction<'T, 'R>) 

你的功能f現在可以寫成(略帶醜陋的語法)作爲PartialFunction<int, int>,保持服用5個輸入,然後返回結果:

let f = 
    NeedsMore(fun a -> NeedsMore(fun b -> 
    NeedsMore(fun c -> NeedsMore(fun d -> 
     NeedsMore(fun e -> Completed(a+b+c+d+e)))))) 

現在,您可以通過解構的參數列表並把它們逐個部分功能實現applyPartially,直到你得到的結果:

let rec applyPartially f items = 
    match f, items with 
    | Completed r, _ -> r 
    | NeedsMore f, head::tail -> applyPartially (f head) tail 
    | NeedsMore _, _ -> failwith "Insufficient number of arguments" 

下現在返回15預期:

applyPartially f [1;2;3;4;5] 
+0

非常感謝,我會讀這個明天,我的大腦傷害的那一刻! :) – Watson

+1

我不是專家,但可以讓f = NeedsMore(好玩的 - >需要更多(好玩的b - > NeedsMore(fun c - > NeedsMore(fun d - > NeedsMore(fun e - > Completed(a + b + c + d + e)))))被封裝在一個計算表達式中? – Watson

+0

@Watson好主意,是的,我想可能是!雖然我猜這不會使代碼_that_比明確的版本更好... –

3

聲明:請不要使用此。這僅僅是evil

let apply f v = 
    let args = v |> Seq.toArray  
    f.GetType().GetMethods() 
    |> Array.tryFind (fun m -> m.Name = "Invoke" && Array.length (m.GetParameters()) = Array.length args) 
    |> function None -> failwith "Not enough args" | Some(m) -> m.Invoke(f, args) 

就像你所期望的:

let f a b c d e= a+b+c+d+e 
apply f [1; 2; 3; 4; 5] //15 
+0

感謝您的笑! ;) – Watson