Являются ли Arrows истинным обобщением функций?

Стрелки часто описываются как обобщение функций (только статически сгенерированные функции, т.е. нет поддержки для частичного приложения/закрытия). Однако, по крайней мере, глядя на стрелки, поскольку они моделируются в Haskell, я не вижу, как они могут обобщать функции из нескольких аргументов, которые возвращают единственный результат (результат, который вообще не может быть кортежем). Я пытаюсь представить себе, как использовать только интерфейс стрелок, чтобы получить композицию стрелок, которая дает единственный результат, который вообще не может быть кортежем. Есть ли способ сделать это или это преднамеренное ограничение силы типа Arrow?

Из того, что я понимаю, стрелки предоставляют возможность составлять статические (возможно параллельные) конвейеры, но они не могут "сбрасывать" кортежи выходов в один конечный результат. Неправильно или я чего-то не хватает?

Ответ 1

Я не вижу, как они могут обобщать функции из нескольких аргументов, которые возвращают единственный результат

Просто введите тип ввода в кортеж, и выведите простое значение. Например, возьмите стрелку

plus :: a (num, num) num
let plus = arr (\(a, b) -> a + b) -- arr (uncurry (+))

В качестве альтернативы вы можете взять "вложенные стрелки" - функция curried с несколькими аргументами - это не что иное, как функция, возвращающая функцию. Таким образом, у нас будет стрелка, результатом которой является еще одна стрелка:

plus :: a num (a num num)
let plus = arr (arr . (+))

и для этого нам нужен экземпляр ArrowApply. Во-первых, вы объедините стрелку с другой стрелкой, которая создаст второй аргумент из вашего ввода

plusWithIncrement :: a num (a num num, num)
let plusWithIncrement = plus &&& arr (+1)

а затем вы можете запустить этот

plusWithIncrement >>> app :: a num num

(что является сложным способом записи arr (\x -> x + (x+1)))

Ответ 2

Вы можете думать о функции с типом

f :: a -> b -> c

как функция, которая принимает значение типа a и создает другую функцию типа b -> c. Другими словами,

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

Обобщение на стрелки довольно просто:

f :: Arrow a (Arrow b c)

Чтобы выполнить композицию функций с несколькими переменными, вам нужно сделать некоторые сумасшедшие семантики-fu с помощью оператора (.) или (<<<) для стрелок. По той же причине, что делает функции с несколькими аргументами бесполезными громоздкими, препятствует синтаксису выражать стрелки таким образом, поэтому существует так много комбинаторов для использования кортежей. Кроме того, ничто не мешает вам определить стрелку, которая отображает кортеж в значение. Функция arr превращает произвольные функции в стрелки!

f :: (a, b) -> c
af :: Arrow (a, b) c
af = arr f