Применение списка аргументов к функции карри с использованием 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) })
Моей первой мыслью было, что здесь будет полезен тип объединения. Я видел, как Майлз Сабин выводил типы профсоюзов с помощью Curry-Howard, поэтому, если это первое предположение верно, то у меня, похоже, есть базовый механизм, необходимый для решения проблемы.
Тем не менее: даже если объединение типов является ответом, было бы полезно, если бы я мог сослаться на «Объединение всех типов от полностью карризованного типа функции до типа функции карри со всеми, кроме последнего предоставленного аргумента». Другими словами, способ превратить тип:
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 или с помощью плагина компилятора, или ни того, ни другого, я не знаю.
Как было отмечено в комментариях ниже, называть результат «тип объединения» не идеально подходит для этого варианта использования. Я не знаю, как еще это назвать, но это самая близкая идея, которая у меня есть на данный момент. Есть ли у других языков особая поддержка этой идеи? Как это будет работать в Coq и Agda?
Назвать эту проблему и понять, где она находится по отношению к более широкой картине (теории типов, разрешимости и т. Д.), Для меня важнее, чем иметь работающую реализациюANSWER
Хотя оба были бы хороши. Бонус указывает любому, кто может установить связь со Скалазом, Моноидами или Теорией категорий в целом.