2014-02-07 20 views
6

我有一個創建Async工作流的函數,以及帶有10個以咖喱風格爲參數的函數。例如如何使用長參數列表來實現無點風格

let createSequenceCore a b c d e f g h i j = 
    async { 
    ... 
    } 

我要創建另一個函數來啓動工作流,所以我有

let startSequenceCore a b c d e f g h i j = 
    Async.StartImmediate (createSequenceCore a b c d e f g h i j) 

有沒有什麼辦法可以擺脫那些多餘的參數?我嘗試了<<運營商,但只能讓我刪除一個運營商。

let startSequenceCore a b c d e f g h i = 
    Async.StartImmediate << (createSequenceCore a b c d e f g h i) 

(我加了Haskell和斯卡拉這個問題即使代碼本身是F#,因爲真的是我想要的只是如何做這樣的討好,這將適用於任何,我認爲Haskell或Scala答案可以很容易地移植到F#並且很可能被標記爲正確答案)。

備註合理地表明,沒有一個簡單的解決方案,這也可以得到賞金。


UPDATE geesh我不會給100分,與這個問題爭論,而不是回答這一個答案,即使是最高的投票,所以在這裏:

我已經有一個創建Async工作流的函數,以及以咖喱風格爲參數的函數。例如

let createSequenceCore a b c d = 
    async { 
    ... 
    } 

我要創建另一個函數來啓動工作流,所以我有

let startSequenceCore a b c d = 
    Async.StartImmediate (createSequenceCore a b c d) 

有沒有什麼辦法可以擺脫那些多餘的參數?我嘗試了<<運營商,但只能讓我刪除一個運營商。

let startSequenceCore a b c = 
    Async.StartImmediate << (createSequenceCore a b c) 
+0

作爲編輯添加了更完整的答案,請查看。 –

回答

9

10個參數聽起來像是太多......怎麼樣你創建10種性質的紀錄,而不是,或可能是杜凡你在每種情況下都不需要全部10個?無論哪種方式,你最終會得到一個單一的參數,並且正常的功能組合按預期工作。

編輯:當你真正需要它,你可以創建<<>>運營商的更強大的版本正是如此:

let (<.<) f = (<<) (<<) (<<) f 
let (<..<) f = (<<) (<<) (<.<) f 
let (<...<) f = (<<) (<<) (<..<) f 

let flip f a b = f b a 
let (>.>) f = flip (<.<) f 
let (>..>) f = flip (<..<) f 
let (>...>) f = flip (<...<) f 

,然後你可以這樣寫:

let startSequenceCore = 
    Async.StartImmediate <...< createSequenceCore 

let startSequenceCore = 
    createSequenceCore >...> Async.StartImmediate 

P.S .:參數f在那裏,以便類型推斷推斷通用參數,而不是obj

2

你可以元組中的參數createSequenceCore

let createSequenceCore(a, b, c, d, e, f, g, h, i, j) = 
    async { 
    ... 
    } 

let startSequenceCore = 
    createSequenceCore >> Async.StartImmediate 
+0

我對'startSequenceCore'中的函數進行了重新排序,以便它可以像從'|>'運算符那樣從左到右讀取。 – mydogisbox

6

正如@Daniel Fabian所提到的,10個參數太多了。根據我的經驗,即使有5個參數太多,代碼也變得不可讀,容易出錯。有這樣的功能通常表明一個糟糕的設計。另請參閱Are there guidelines on how many parameters a function should accept?

但是,如果您堅持,可以使其成爲無點,但我懷疑它會獲得任何好處。我將在Haskell中舉一個例子,但我相信它也很容易移植到F#。訣竅是嵌套函數組合操作:

data Test = Test 
    deriving (Show) 

createSequenceCore :: Int -> Int -> Int -> Int -> Int 
        -> Int -> Int -> Int -> Int -> Int -> Test 
createSequenceCore a b c d e f g h i j = Test 

-- the original version 
startSequenceCore :: Int -> Int -> Int -> Int -> Int 
        -> Int -> Int -> Int -> Int -> Int -> IO() 
startSequenceCore a b c d e f g h i j = 
    print (createSequenceCore a b c d e f g h i j) 

-- and point-free: 
startSequenceCore' :: Int -> Int -> Int -> Int -> Int 
        -> Int -> Int -> Int -> Int -> Int -> IO() 
startSequenceCore' = 
    (((((((((print .) .) .) .) .) .) .) .) .) . createSequenceCore 

更換f(f .)升降機的函數的工作內的一個參數,因爲我們可以通過添加括號的(.)類型見:

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

另請參閱Conal Elliott撰寫的這篇照片博客文章:Semantic editor combinators

+1

我很想說如果沒有一個有意義的抽象層,那麼_anything_的數量太多了。就像[如果你遇到一個高於8.7的數字,你沒有做真正的數學](http://xkcd.com/899/)。 – leftaroundabout

+0

@leftaroundabout不錯! –

1

我假設您只是想編寫乾淨的代碼,而不是允許一次捲曲一個參數。

只需編寫您自己的composeN函數。

let compose4 g f x0 x1 x2 x4 = 
    g (f x0 x1 x2 x4) 

let startSequenceCore = 
    compose4 Async.StartImmediate createSequenceCore