Применение списка аргументов к каррированной функции с помощью foldLeft в Scala

Можно ли сделать foldLeft для списка аргументов, где начальное значение, передаваемое в свертку, является полностью каррированной функцией, оператором это apply , а список представляет собой список аргументов, которые необходимо передать функции f ?

Например, предположим, что f определяется как:

scala> val f = (i: Int, j: Int, k: Int, l: Int) => i+j+k+l
f: (Int, Int, Int, Int) => Int = <function4>

Что мы можем из конечно, используйте напрямую:

scala> f(1, 2, 3, 4)
res1: Int = 10

Или карри и применяйте аргументы по одному:

scala> f.curried
res2: Int => Int => Int => Int => Int = <function1>

scala> f.curried.apply(1).apply(2).apply(3).apply(4)
res3: Int = 10

На первый взгляд это выглядит как работа для foldLeft .

Моя первая попытка описать последовательность apply с использованием foldLeft выглядит так:

scala> List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })

Однако это приводит к следующей ошибке:

<console>:9: error: type mismatch;
 found   : Int => Int => Int => Int
 required: Int => Int => Int => Int => Int
              List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })

Мое прочтение сообщения об ошибке неверно. этот вывод типа потребует некоторой подсказки для g .

Решение, которое я ищу, оставляет все неизменным в моем исходном выражении, кроме типа g :

List(1, 2, 3, 4).foldLeft(f.curried)({ (g: ANSWER, x) => g.apply(x) })

Моя первая мысль заключалась в том, что здесь будет полезен тип объединения. Я видел, как Майлз Сабин выводил типы объединения с помощью Карри-Ховарда, так что, если эта первая догадка верна, то, похоже, у меня есть базовый механизм, необходимый для решения проблемы.

Однако: даже если типы объединения являются ответом, было бы полезно, если бы я мог сослаться на «Объединение всех типов от полностью каррированного типа функции до типа каррированной функции со всеми, кроме последнего предоставленного аргумента» . Другими словами, способ превратить тип:

T1 => ... => Tn

в тип объединения:

(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)

будет полезен в качестве типа для g выше.

Выполнение foldLeft в списке ограничивает обсуждение случаем, когда от T1 до Tn-1 все одинаковы. Обозначения, подобные

(T1 =>)+ Tn

, описывают тип, который я хочу предоставить для g .

Конкретный случай, о котором я спрашиваю, не требует произвольно длинных цепочек, поэтому мы могли бы указать границы итератора, используя

(T1 =>){1,4} Tn

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

Suffixes(T1 => ... => Tn)

Реализация этого выходит далеко за рамки моих возможностей Scala на данный момент. Любые намеки на то, как это сделать, будут оценены. Я не знаю, можно ли это сделать с расширенным использованием существующей системы типов Scala или через плагин компилятора, или ни то, ни другое.

Как было отмечено в комментариях ниже, называть результат «тип объединения» не совсем подходит для этого варианта использования. Я не знаю, как это еще назвать, но это самая близкая идея, которая у меня есть на данный момент.Есть ли у других языков особая поддержка этой идеи? Как это будет работать в Coq и Agda?

Назвать эту проблему и понять, где она находится по отношению к более широкой картине (теории типов, разрешимости и так далее), для меня важнее, чем наличие работающей реализации ] ОТВЕТ , хотя и то, и другое было бы неплохо. Бонусные баллы всем, кто может связать себя со Scalaz, моноидами или теорией категорий в целом.

20
задан Adam Pingel 12 February 2012 в 03:47
поделиться