2012-08-26 125 views
18

如果我想更改函數中參數的順序,該怎麼辦?如何更改參數的順序?

flip

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

,但我不明白如何使它爲參數的數量較多的工作。有沒有一種通用的方法來排列論據?

+0

@phimuemue它可能不是一個函數,但TH宏。是的,這樣的宏可以寫成,但簡單的lambda幾乎一樣短。 – permeakra

+5

如果您傾向於有很多參數,則可能錯過創建適當數據類型的機會。或者你只是一個喋喋不休的人。 – Landei

回答

12

一般而言,最好的方法就是手動完成。假設你有一個函數

f :: Arg1 -> Arg2 -> Arg3 -> Arg4 -> Res 

願與您

g :: Arg4 -> Arg1 -> Arg3 -> Arg2 -> Res 

那麼你就寫

g x4 x1 x3 x2 = f x1 x2 x3 x4 

如果你需要一個特定的排列幾次,那麼你當然可以從中抽象,如flip對於雙參數的情況:

myflip :: (a4 -> a1 -> a3 -> a2 -> r) -> a1 -> a2 -> a3 -> a4 -> r 
myflip f x4 x1 x3 x2 = f x1 x2 x3 x4 
+2

我認爲這是最好的方式來做到這一點,如果你需要對參數進行專門的重新排列,最容易定義你自己的函數來做到這一點,但我懷疑其中任何一個都可以用flip的組合來生成,而lambda就像(\ x - > flip $ fx),該函數部分應用該函數來翻轉除第一個和第二個之外的參數。 –

32

如果你喜歡的編輯功能,他們寫完後,你真的應該讀 Conal Elliott的優秀博客文章語義編輯組合子

http://conal.net/blog/posts/semantic-editor-combinators

其實,每個人都應該反正閱讀。這是一個真正有用的 方法(我在這裏濫用)。 Conal使用更多的構造,而不僅僅是resultflip以非常靈活的效果。

result :: (b -> b') -> ((a -> b) -> (a -> b')) 
result = (.) 

假設我有一個使用3個參數

use3 :: Char -> Double -> Int -> String 
use3 c d i = c: show (d^i) 

,我想掉前兩個,我只是用flip use3像你說的, 功能,但如果我想交換第二個和第三個,我想要的是將flip 應用到use3到它的第一個參數的結果。

use3' :: Char -> Int -> Double -> String 
use3' = (result) flip use3 

讓我們一起移動和交換的功能use5使用5

use5 :: Char -> Double -> Int -> (Int,Char) -> String  -> String 
use5' :: Char -> Double -> Int -> String  -> (Int,Char) -> String 

use5 c d i (n,c') s = c : show (d^i) ++ replicate n c' ++ s 

我們需要申請flip施加use5它的結果是前三個參數的第四個和第五個參數, 所以這就是結果的結果:

use5' = (result.result.result) flip use5 

爲什麼不保存思考以後再想並定義爲

swap_1_2 :: (a1 -> a2 -> other) -> (a2 -> a1 -> other) 
swap_2_3 :: (a1 -> a2 -> a3 -> other) -> (a1 -> a3 -> a2 -> other) 
--skip a few type signatures and daydream about scrap-your-boilerplate and Template Haskell  

swap_1_2 = flip  
swap_2_3 = result flip 
swap_3_4 = (result.result) flip 
swap_4_5 = (result.result.result) flip 
swap_5_6 = (result.result.result.result) flip 

...這就是你應該停下來的地方,如果你喜歡簡單和優雅。 請注意,類型other可能是b -> c -> d,因爲神話般的庫裏和->, , 的右關聯性,swap_2_3適用於一個函數,它可以接受任意數量的上面兩個參數。 對於任何更復雜的情況,您應該手動編寫一個置換函數。下面的內容僅僅是爲了知識的好奇。

現在,交換第二個和第四個參數怎麼辦? [旁白:有一個定理,我從任何排列可製成交換相鄰項的組成我的代數講座 記得了。]

我們可以做這樣的: 第1步:移動2旁邊4( swap_2_3

a1 -> a2 -> a3 -> a4 -> otherstuff 
a1 -> a3 -> a2 -> a4 -> otherstuff 

有使用swap_3_4

a1 -> a3 -> a2 -> a4 -> otherstuff 
a1 -> a3 -> a4 -> a2 -> otherstuff 

交換它們然後再次使用swap_2_3交換4回至位置2:

a1 -> a3 -> a4 -> a2 -> otherstuff 
a1 -> a4 -> a3 -> a2 -> otherstuff 

所以

swap_2_4 = swap_2_3.swap_3_4.swap_2_3 

也許有,有很多結果 的越來越有直接的更簡潔的方式和翻轉,但隨機搞亂沒找到我!

同樣,交換1和5,我們可以用5搬過來1〜4,交換,移動5回從4比1

swap_1_5 = swap_1_2.swap_2_3.swap_3_4 . swap_4_5 . swap_3_4.swap_2_3.swap_1_2 

或者,如果你願意,你可以通過在翻轉重用swap_2_4結束 (用2交換1和用4交換5),swap_2_4然後再翻轉兩端。

swap_1_5' = swap_1_2.swap_4_5. swap_2_4 .swap_4_5.swap_1_2 

當然它更容易界定

swap_1_5'' f a b c d e = f e b c d a 

它有明確的是,consise,高效的優點,並在ghci中沒有明確標註是一個有用的類型簽名。

但是,這是一個非常有趣的問題,謝謝。