Хаскелл - составление трех функций странным образом

У меня есть три функции xyz и функция, называемая functionComposer.

Я хочу, чтобы functionComposer имел в качестве аргументов функции xyz и возвращал мне функцию, которая использует результат y и z как аргументы в x и применяет x.

В математических обозначениях: x(y(a),z(b))

Я не прошу об этом: functionComposer xyz = xyz

Например:

****** x = x + x

summer x y = x + y

functionComposer summer ****** ****** = summer (******) (******)

если x = 2, результат должен быть равен 8 (2 + 2) + (2 + 2)

4 ответа

Я как-то чувствую, что вы так или иначе хотите путать серии точек, так что:

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

который приходит "естественно" из

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

Но зачем останавливаться?

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

Больше не надо:

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

Больше!

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


Вы также можете использовать аппликативный экземпляр для (->) a так, чтобы

import Control.Applicative


funcComp summer ******* ******* = summer <$> ******* <*> *******

Или пример монады

funcComp summer ******* ******* = liftM2 summer ******* *******

Способ понять это состоит в том, что для (->) a, как аппликативный, так и монодарный экземпляр предназначены для "параметризации" над значением функции, которое ******* и ******* принимают.


Используя ваши обозначения:

functionComposer summer ******* ******* = \x -> summer (******* x) (******* x)

\x ->... представляет функцию отображения x в ...

Примечание. Я должен был дать разные имена аргументу ****** функции, поскольку в целом вы хотите создавать разные функции.


Вы в основном оцениваете y и z "параллельно 1 ". Наиболее фундаментальным комбинатором для выражения является (***) :: Arrow f => fac → fbd → f (a, b) (c, d). В результате вы хотите прокормить x, так что в основном вы хотели бы написать

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

Теперь это не совсем трюк, потому что комбинаторы стрелок работают с кортежами. Поэтому вам нужно разогнать x. Точно так же, если вы хотите, чтобы вся вещь принимала аргументы в обычном карри, вы должны прочитать кортеж (a,b). Достаточно легко:

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

1 Разум, я не имею в виду параллель в смысле многопоточности, только "семантически параллельный".

licensed under cc by-sa 3.0 with attribution.