简体   繁体   English

Haskell-以奇怪的方式组成三个函数

[英]Haskell- composing three functions in weird way

I have three functions xyz and a function called functionComposer. 我有三个函数xyz和一个名为functionComposer的函数。

I want functionComposer to have as arguments the functions xyz and to return me a function that uses the result of y and z as arguments into x and applies x. 我希望functionComposer将函数xyz作为参数,并返回一个函数,该函数使用y和z的结果作为x的参数并应用x。

In mathematical notation: x(y(a),z(b)) 在数学符号中: x(y(a),z(b))

Im NOT asking for this : functionComposer xyz = xyz 我不是要求这个: functionComposer xyz = xyz

For example: 例如:

double x = x + x

summer x y = x + y

functionComposer summer double double = summer (double) (double) 

if x = 2 the result should be 8 (2+2)+(2+2) 如果x = 2,结果应为8(2 + 2)+(2 + 2)

You can also use the applicative instance for (->) a like so 你也可以使用(->) a的应用实例

import Control.Applicative


funcComp summer double1 double2 = summer <$> double1 <*> double2

Or the monad instance 或monad实例

funcComp summer double1 double2 = liftM2 summer double1 double2

The way to understand this is that for (->) a , both the applicative and the monad instance are meant to "parametrize" over the function value that double1 and double2 both accept. 理解这一点的方法是,对于(->) a ,applicative和monad实例都是为了“参数化” double1double2都接受的函数值。

Using your notation: 使用你的符号:

functionComposer summer double1 double2 = \x -> summer (double1 x) (double2 x) 

The \\x -> ... represents the function mapping x to the ... . \\x -> ...表示将x映射到...的函数。

Note I had to give different names to the double function argument, since in general you want to compose different functions. 注意我必须给double函数参数赋予不同的名称,因为通常你想要组合不同的函数。

I somehow feel as if you wanted a confusing series of dots anyways, so: 不管怎样,我觉得好像你想要一系列令人困惑的点,所以:

functionComposer :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e
functionComposer x y z = (. z) . (x . y)

which comes “naturally” from 这是“自然地”来自

functionComposer x y z a = (x . y) a . z

But why stop there? 但为何停在那里?

functionComposer x y = (. (x . y)) . flip (.)

No, more: 不再:

functionComposer x = (. flip (.)) . flip (.) . (x .)

More! 更多!

functionComposer = (((. flip (.)) . flip (.)) .) . (.)

You're basically evaluating y and z "in parallel 1 ". 你基本上是在评估yz “并行1 ”。 The most fundamental combinator to express this is (***) :: Arrow f => fac -> fbd -> f (a, b) (c, d) . 表达这个的最基本的组合是(***) :: Arrow f => fac -> fbd -> f (a, b) (c, d) The result of that you want to feed to x , so basically you'd like to write 你想要提供给x ,所以基本上你想写

           x . (y***z)            -- or  x <<< y***z

Now that doesn't quite do the trick because the arrow combinators work with tuples. 现在这并没有完全解决问题,因为箭头组合器与元组一起工作。 So you need to uncurry x . 所以你需要uncurry x Much the same way, if you want the entire thing to accept the arguments in the normal curried fashion, then you must curry out the (a,b) tuple. 大致相同的方式,如果你想让整个事物以正常的方式接受论证,那么你必须讨论(a,b)元组。 Easy enough though: 虽然很容易:

functionComposer :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e
functionComposer x y z = curry $ uncurry x <<< y *** z

1 Mind, I don't mean parallel in the multithreading sense, only "semantically parallel". 1介意,我不是指多线程意义上的并行,只是“语义平行”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM