Это довольно легко определить оператор, какУплотненное применение функции
(@) :: [x -> y] -> [x] -> [y]
, которая принимает список функций и список входов и возвращает список результатов. Есть два очевидных способа реализации этого:
- Нанести первую функцию к первому входу, второй функции на второй вход и т.д.
- Применить все функции для каждого входа.
Либо одинаково тривиально определить. Приятно, что теперь вы можете сделать что-то вроде
foo :: X -> Y -> Z -> R
bar :: [X] -> [Y] -> [Z] -> [R]
bar xs ys zs = [foo] @@ xs @@ ys @@ zs
Это обобщает на произвольное число аргументов функции.
Пока все хорошо. Теперь проблема: Как изменить тип подписи для @@
, что тип подписи для bar
становится
bar :: [X] -> [Y] -> [Z] -> [[[R]]]
Это не трудно реализовать функцию с этим типом; любой из них сделает это:
bar xs ys zs = map (\ x -> map (\ y -> map (\ z -> foo x y z) zs) ys) zs
bar xs ys zs = map (\ z -> map (\ y -> map (\ x -> foo x y z) xs) ys) zs
Я не суетливый, о каком результате я получаю. Но я не могу понять, как настроить оператора @@
для этого.
Очевидная вещь, чтобы попытаться это
(@@) :: [x -> y] -> [x] -> [[y]]
Это не сложно реализовать, но это не поможет. Теперь у вас есть
[foo] @@ xs :: [[Y -> Z -> R]]
, который не является допустимым для ввода @@
. Нет очевидного способа узнать, сколько уровней списков доступно для доступа к функции; очевидно, что этот подход является тупиком.
Я пробовал несколько других возможных типов подписей, но ни один из них не приближает меня к ответу. Может ли кто-нибудь дать мне решение или объяснить, почему никто не существует?
Используйте класс. – dave4420
Неповторимый вопрос, однако ваша оригинальная '(@@)' (вторая версия) эквивалентна экземпляру 'Applicative' для списков. Первая версия, которая применяет каждую функцию к каждому вводу, является экземпляром «Applicative» для нового типа «ZipList». –
В чем разница между «каждым» и «каждым»? – Prateek