Можно ли сделать 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) })
Моя первая мысль заключалась в том, что здесь будет полезен тип объединения. Я видел, как Майлз Сабин выводит типы профсоюзов с помощью Curry-Howard, поэтому, если эта первая догадка истинна, то у меня, похоже, есть основной механизм, необходимый для решения проблемы.
Однако: даже если типы объединения являются ответом, было бы полезно, если бы я мог ссылаться на "объединение всех типов из полностью карриного типа функции в тип функции curried со всеми, кроме последнего аргумента", Другими словами, способ обращения к типу:
T1 => ... => Tn
в тип объединения:
(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)
будет полезен как тип для g
выше.
Выполнение foldLeft
в List
ограничивает обсуждение в случае, когда T1
через Tn-1
все одинаковы. Обозначение типа
(T1 =>)+ Tn
будет описывать тип, который я хочу предоставить для g
.
В конкретном случае, о котором я спрашиваю, не требуются сколь угодно длинные цепочки, поэтому мы можем предоставить ограничения на итераторе, используя
(T1 =>){1,4} Tn
Заглядывая в будущее, желая сделать это для цепочек типов, которые не равны, хотя, возможно, какая-то магическая функция для типов, которые перекосят цепочку в набор всех суффиксов, более полезна:
Suffixes(T1 => ... => Tn)
Реализация этого намного превосходит мои способности Scala на данный момент. Любые намеки относительно того, как это сделать, будут оценены. Можно ли это сделать с расширенным использованием системы Scala существующего типа или с помощью плагина компилятора или ни того, что я не знаю.
Как было отмечено в комментариях ниже, при вызове результата "тип объединения" не подходит для этого варианта использования. Я не знаю, что еще назвать, но это самая близкая идея, которую я имею в данный момент. У других языков есть особая поддержка этой идеи? Как это будет работать в Кок и Агда?
Именование этой проблемы и понимание того, где она сидит по отношению к большей картине (теории типов, разрешимости и т.д.), важнее для меня, чем выполнение рабочей реализации ANSWER
, хотя оба они были бы хороши. Бонус указывает на всех, кто может подключаться к Scalaz, Monoids или Category Theory вообще.