Можно ли сделать 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
, хотя оба были бы хороши.Бонусные очки начисляются всем, кто может подключиться к Скалазу, Моноидам или Теории категорий в целом.