Сегодня понадобилось сделать "typeclass"-аналог натурального преобразования со следующей сигнатурой:
trait LiftF[F[_], G[_]] {Естественно, каждый раз писать в контекстных ограничениях что-то вроде
def liftF[A](fa: F[A]): G[A]
}
F[_]: LiftF[?[_], G]]
уже довольно удобно, но хочется иметь возможность делать это максимально лаконично, к примеру, так: F[_]: LiftF.To[G]
. В данном случае тип To[G[_]]
после применения к G
возвращал бы type-лямбду LiftF[?[_], G]
, то есть, по сути, являлся бы аналогом частично применённого конструктора типов из Haskell.К сожалению, эта затея не увенчалась успехом - Scala не поддерживает определение "недоприменённых" типов через ключевое слово
type
- все параметры должны быть вынесены в сигнатуру типа. При этом использование аналога Aux паттерна приводит к ещё более неудобному синтаксису:trait To[G[_]] {Тем не менее, эта заметка не появилась бы в канале, если бы этим всё и ограничилось. Оказывается, в Scala 3 уже есть возможность записывать частично-применённые типы без каких-либо плагинов и библиотек. Вот так в Dotty будет выглядеть реализация типа
type From[F[_]] = LiftF[F, G]
}
def func[A, G[_], F[_]: LiftF.To[G]#From](a: F[A]): G[A]
To
:type To[G[_]] = [F[_]] => LiftF[F, G]Таким образом, появилась ещё одна отличная причина ждать/уже сейчас пробовать Dotty.
>>Click here to continue<<