如果我想更改函数中参数的顺序,该怎么办?如何更改参数的顺序?
有flip
:
flip :: (a -> b -> c) -> b -> a -> c
,但我不明白如何使它为参数的数量较多的工作。有没有一种通用的方法来排列论据?
如果我想更改函数中参数的顺序,该怎么办?如何更改参数的顺序?
有flip
:
flip :: (a -> b -> c) -> b -> a -> c
,但我不明白如何使它为参数的数量较多的工作。有没有一种通用的方法来排列论据?
一般而言,最好的方法就是手动完成。假设你有一个函数
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
我认为这是最好的方式来做到这一点,如果你需要对参数进行专门的重新排列,最容易定义你自己的函数来做到这一点,但我怀疑其中任何一个都可以用flip的组合来生成,而lambda就像(\ x - > flip $ fx),该函数部分应用该函数来翻转除第一个和第二个之外的参数。 –
如果你喜欢的编辑功能,他们写完后,你真的应该读 Conal Elliott的优秀博客文章语义编辑组合子
http://conal.net/blog/posts/semantic-editor-combinators
其实,每个人都应该反正阅读。这是一个真正有用的 方法(我在这里滥用)。 Conal使用更多的构造,而不仅仅是result
和flip
以非常灵活的效果。
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中没有明确标注是一个有用的类型签名。
但是,这是一个非常有趣的问题,谢谢。
@phimuemue它可能不是一个函数,但TH宏。是的,这样的宏可以写成,但简单的lambda几乎一样短。 – permeakra
如果您倾向于有很多参数,则可能错过创建适当数据类型的机会。或者你只是一个喋喋不休的人。 – Landei