如何改变参数的顺序?

Yro*_*irg 21 haskell

如果我想更改函数中参数的顺序怎么办?

flip:

flip :: (a -> b -> c) -> b -> a -> c
Run Code Online (Sandbox Code Playgroud)

但我不知道如何让它适用于更多的论点.是否有一般方法来置换参数?

And*_*ewC 36

如果您想在编写后编辑函数,那么您真的应该阅读Conal Elliott的优秀博客文章语义编辑器组合器

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

事实上,无论如何,每个人都应该阅读它.这是一个真正有用的方法(我在这里滥用).Conal使用更多的结构不仅仅是resultflip以非常灵活的效果.

result :: (b -> b') -> ((a -> b) -> (a -> b'))
result =  (.)
Run Code Online (Sandbox Code Playgroud)

假设我有一个使用3个参数的函数

use3 :: Char -> Double -> Int -> String
use3 c d i = c: show (d^i)
Run Code Online (Sandbox Code Playgroud)

我想交换的前两个,我只用flip use3像你说的,但如果我想交换seconnd第三,我要的是适用flip 于应用的结果,use3它的第一个参数.

use3' :: Char -> Int -> Double -> String
use3' = (result) flip use3
Run Code Online (Sandbox Code Playgroud)

让我们继续并交换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
Run Code Online (Sandbox Code Playgroud)

我们需要flip应用use5到它的前三个参数的结果,所以这是结果的结果:

use5' = (result.result.result) flip use5
Run Code Online (Sandbox Code Playgroud)

为什么不在以后保存思考并定义

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
Run Code Online (Sandbox Code Playgroud)

......如果你喜欢简约和优雅,那就应该停下来.请注意,类型other可能是b -> c -> d因为美妙的Curry和正确的关联性->,swap_2_3适用于一个函数,它接受任意数量的参数超过两个.对于任何更复杂的事情,你应该亲自编写一个置换函数.以下内容仅仅是为了求知欲.

现在,如何交换第二和第四个参数?[旁白:从我的代数讲座中我记得有一个定理,任何排列都可以作为交换相邻项目的组合.]

我们可以这样做:第1步:在4旁边移动2(swap_2_3)

a1 -> a2 -> a3 -> a4 -> otherstuff
a1 -> a3 -> a2 -> a4 -> otherstuff
Run Code Online (Sandbox Code Playgroud)

用它们交换它们 swap_3_4

a1 -> a3 -> a2 -> a4 -> otherstuff
a1 -> a3 -> a4 -> a2 -> otherstuff
Run Code Online (Sandbox Code Playgroud)

然后swap_2_3再次使用4将4换回到位置2 :

a1 -> a3 -> a4 -> a2 -> otherstuff
a1 -> a4 -> a3 -> a2 -> otherstuff
Run Code Online (Sandbox Code Playgroud)

所以

swap_2_4 = swap_2_3.swap_3_4.swap_2_3
Run Code Online (Sandbox Code Playgroud)

也许有一种更简洁的方式直接到达那里有很多结果和翻转,但随机搞乱并没有找到它!

同样,交换1和5我们可以将1移动到4,与5交换,从4移动5到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
Run Code Online (Sandbox Code Playgroud)

或者如果你愿意,你可以swap_2_4通过翻转结束重复使用(用2和5交换1和4),然后再次在末尾翻转.

swap_1_5' = swap_1_2.swap_4_5. swap_2_4 .swap_4_5.swap_1_2
Run Code Online (Sandbox Code Playgroud)

当然,定义起来要容易得多

swap_1_5'' f  a b c d e = f  e b c d a
Run Code Online (Sandbox Code Playgroud)

它具有清晰,明确,高效的优点,并且在没有明确注释的情况下在ghci中具有有用的类型签名.

然而,这是一个非常有趣的问题,谢谢.

  • 或者,对于不那么理智的人,`swap_5_6 =((((flip。)。)。)。)`和`swap_2_4 =(flip。)。((flip。)。)。(flip。)`。 (2认同)

kos*_*kus 12

一般来说,最好的方法就是手动完成.假设你有一个功能

f :: Arg1 -> Arg2 -> Arg3 -> Arg4 -> Res
Run Code Online (Sandbox Code Playgroud)

你想要的

g :: Arg4 -> Arg1 -> Arg3 -> Arg2 -> Res
Run Code Online (Sandbox Code Playgroud)

然后你写

g x4 x1 x3 x2 = f x1 x2 x3 x4
Run Code Online (Sandbox Code Playgroud)

如果你需要多次特定的排列,那么你当然可以从中抽象出来,就像flip两个论证的情况一样:

myflip :: (a4 -> a1 -> a3 -> a2 -> r) -> a1 -> a2 -> a3 -> a4 -> r
myflip f x4 x1 x3 x2 = f x1 x2 x3 x4
Run Code Online (Sandbox Code Playgroud)

  • 我觉得这是做的最好的方法,如果你需要的参数专门的重排,这是最简单的定义自己的函数来做到这一点,但我怀疑任何一个可以翻转的组合物生成,lambda表达式像(\ X - >翻转$ fx)部分应用函数来翻转第一个和第二个以外的参数. (2认同)