Частично применяемые параметры типа
Я отчаянно пытаюсь решить следующее:
trait Access[Res[_]] { def access[C]: Res[C] }
trait CList[C1, A] extends Access[CList[_, A]] // ?!
def test[C1, C2, A](c: CList[C1, A]): CList[C2, A] = c.access[C2]
scalac просто говорит: "error: illegal cyclic reference involving trait CList"
. как это сделать?
Ответы
Ответ 1
Вам может быть интересен тип lambdas. Частичное приложение, которое вы использовали в своем ответе, на самом деле реализовано в scalaz.
Поскольку код, как правило, становится менее читаемым, но вместо этого они начали использовать тип lambdas. Тип, о котором идет речь, может быть записан как
({type λ[α] = CList[α,A]})#λ
Это работает, создавая проекцию типа параметризованного типа λ
внутри структурного типа, таким образом захватывая параметр внешнего типа (в данном случае A
).
Другая проблема, связанная с дисперсией, описанной в вашем ответе, может быть решена, если сделать параметр Res
в Access
ковариантным.
После этих изменений ваш код должен выглядеть так:
trait Access[+Res[_]] { def access[C] : Res[C]}
trait CList[C, +A] extends Access[({type λ[α] = CList[α,A]})#λ]
Ответ 2
googling для "приложения с частичным типом" Я нашел это решение, отправленное Джеймсом Ири в списке дискуссий scala (http://scala-programming-language.1934581.n4.nabble.com/Partial-type-inference-td2007311.html; поэтому порядок arg изменяется):
type Partial2[T[_,_], B] = {
type Apply[A] = T[A,B]
}
trait CList[C1, A] extends Access[Partial2[CList, A]#Apply]
cheese louise, это действительно единственный способ сделать это в scala в 2011 году?!!
EDIT:
Это не выполняется с ковариацией в A
:, - (
trait Access[Res[_]] { def access[C]: Res[C] }
type Partial2[T[_,_], B] = {
type Apply[A] = T[A,B]
}
trait CList[C1, +A] extends Access[Partial2[CList, A]#Apply]
"covariant type A occurs in invariant position"
Ответ 3
Просто для обновления добавьте этот плагин компилятора в ваш sbt для доброй проекции, и вы получите хороший синтаксис, используя ?
,
Это удаляет типовой шаблон проекции, который выглядит грязным!
Таким образом, вы можете написать что-то вроде Either[String,?]
addCompilerPlugin ("org.spire-math" %% "kind-Проектор"% "0.9.7")
он реализован с той же проекцией старого типа под
Вы также можете найти его здесь:
https://underscore.io/blog/posts/2016/12/05/type-lambdas.html
Ответ 4
Я знаю, что это действительно старый вопрос, но в любом случае:
trait AnyAccess {
type Res[X]
def access[Z]: Res[Z]
}
trait AnyCList extends AnyAccess { me =>
type C
type A
// this could be a subtype bound instead, if needed
type Res[X] = AnyCList { type C = X; type A = me.A }
}
case object AnyCList {
type of[C0, +A0] = AnyCList { type C = C0; type A <: A0 }
}
case object buh {
def test[C1, C2, A](c: AnyCList.of[C1, A]): AnyCList.of[C2, A] = c.access[C2]
}
Ответ 5
Вот метод, который работал для меня, чтобы "частично применить параметры типа":
У меня была такая функция
def foo[A, B, C, D, E](...)
Так что мне нужно было указать только один параметр типа, чтобы компилятор мог вывести остальное. Это сработало для меня:
object InferType {
type InferType[A] = Option[A]
def apply[A]: Option[A] = None
}
Обновите foo, чтобы получить дополнительный параметр типа InferType:
// t parameter is unused in implementation but
// is used by compiler to infer other type parameters
def foo[A, B, C, D, E](..., t: InferType[D])
Использование:
foo(..., InferType[ConcreteD])