Что мне не хватает: возможна ли композиция функции с несколькими аргументами?

Я понимаю основы композиции функций в F #, как, например, описано здесь.

Возможно, я что-то упускаю. Операторы >> и <<, похоже, были определены с предположением, что каждая функция принимает только один аргумент:

> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>
> (<<);;
val it : (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b) = <fun:it@215-14>

Однако я хотел бы сделать что-то вроде следующего:

let add a b = a + b
let double c = 2*c
let addAndDouble = add >> double   // bad!

Но даже несмотря на то, что вывод add относится к типу, необходимому для ввода double, он отклоняется.

Я знаю, что могу переписать add с одним аргументом кортежа:

let add (a,b) = a + b

Или я могу написать новый оператор для каждого количества возможных аргументов первой функции:

let inline (>>+) f g x y = g (f x y)
let doubleAdd = add >>+ double

Но это кажется глупым! Есть ли лучший способ, который я пропустил?


person Kevin Cantu    schedule 26.03.2011    source источник


Ответы (3)


То, что вы хотите, не является совершенно необоснованным, но не было бы никакого способа указать тип обобщенного оператора композиции в системе типов F #. То есть нет хорошего способа объединить

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

и

(>>+) : ('a -> 'b -> 'c) -> ('c -> 'd) -> 'a -> 'b -> 'd

(не говоря уже о бесконечном количестве версий с более высокой степенью арности). Следовательно, у вас нет другого выбора, кроме как определить свои собственные дополнительные операторы. На практике я часто нахожу код, написанный в «остроконечном» стиле let f x y = add x y |> double, в любом случае более читабельным, чем безточечный / «бессмысленный» let f = add (>>+) double.

person kvb    schedule 27.03.2011
comment
Особенно, когда вам нужно flip выполнять свои функции. - person Alexey Romanov; 27.03.2011

Посмотрите на типы >> и <<, которые вы разместили выше. например:

> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>

Он принимает две функции и значение ('a) и возвращает другое значение. Вам нужно что-то, что принимает две функции и 2 значения. Следовательно, и >>, и << не имеют правильной сигнатуры типа.

Ваша реализация совсем не глупа. Просто ваше требование не входит в стандартную комплектацию библиотек F #. Будьте благодарны за то, что у вас есть язык, который позволяет вам определять такие собственные операторы :)

person OJ.    schedule 27.03.2011

Как насчет того, чтобы пропустить стек аргументов?

let add = function x :: y :: t -> x + y :: t
let double = function x :: t -> 2 * x :: t

Затем вы можете составить произвольные функции арности:

let doubleAdd = add >> double

И это работает:

> doubleAdd [7; 14]
42

(см. также Состав функций F # с несколькими входными параметрами )

person AshleyF    schedule 21.04.2011