Это немного непонятно, хотя и разрешено использование псевдонимов типов. В спецификации вы можете прочитать псевдоним типа может использоваться для ссылки на некоторый абстрактный тип и использоваться как ограничение типа, предлагая компилятору, что должно быть разрешено.
Итак код из вопроса
def apply(f: F[Arbitrary] => Arbitrary): Capture[F] = new Capture[F] {
def continue[A](k: F[A]): A = f(k.asInstanceOf[F[Arbitrary]]).asInstanceOf[A]
}
можно прочитать как: у нас есть Arbitrary
тип, о котором мы ничего не знаем, но мы знаем, что если мы поместим F[Arbitrary]
в функцию, мы получим Arbitrary
.
Дело в том, что компилятор не позволит вам передать любое значение как Arbitrary
, поскольку он не может доказать, что ваше значение относится к этому типу. Если бы это могло доказать, что Arbitrary=A
вы могли бы просто написать:
def apply(f: F[Arbitrary] => Arbitrary): Capture[F] = new Capture[F] {
def continue[A](k: F[A]): A = f(k)
}
Однако, это невозможно, поэтому вы вынуждены использовать .asInstanceOf
. Вот почему type X
не равносильно высказыванию type X = Any
.
Есть причина, почему мы не просто используем дженерики. Как бы вы передали полиморфную функцию внутри? Тот, который делает F[A] => A
для любого A
? Одним из способов будет использование естественного преобразования (или ~>
или FunctionK
) из F[_]
в Id[_]
. Но как грязно было бы его использовать!
// no capture pattern or other utilities
new Capture[F] {
def continue[A](fa: F[A]): A = ...
}
// using FunctionK
object Capture {
def apply[F[_]](fk: FunctionK[F, Id]): Caputure[F] = new Capture[F] {
def continue[A](fa: F[A]): A = fk(fa)
}
}
Capture[F](new FunctionK[F, Id] {
def apply[A](fa: F[A]): A = ...
})
Не приятно. Проблема в том, что вы не можете передать что-то вроде полиморфной функции (здесь [A]: F[A] => A
). Вы можете передать экземпляр только полиморфным методом (то есть FunctionK
работает).
Таким образом, мы взломали это, передав мономорфную функцию с A
фиксированным для типа, который вы не можете создать (Arbitrary
), потому что ни один компилятор типов не может доказать, что он соответствует Arbitrary
.
Capture[F](f: F[Arbitrary] => Arbitrary): Capture[F]
Затем вы заставляете компилятор думать, что он имеет тип F[A] => A
, когда вы изучаете A
.
f(k.asInstanceOf[F[Arbitrary]]).asInstanceOf[A]
Другая часть шаблона - это частичное применение параметров типа sort. Если вы сделали все за один раз:
object Capture {
type Constructors[F[_]] = F[Capture[F]]
type Arbitrary
def apply[F[_]](f: F[Arbitrary] => Arbitrary): Capture[F] = new Capture[F] {
def continue[A](k: F[A]): A = f(k.asInstanceOf[F[Arbitrary]]).asInstanceOf[A]
}
}
у вас могут возникнуть проблемы, например, передача Capture.apply
как нормальная функция. Вам придется делать такие вещи, как otherFunction(Capture[F](_))
. Создав Apply
"фабрику", мы можем разделить приложение параметров типа и передать функцию F[Arbitrary] => Arbitrary
.
Короче говоря, речь идет о том, чтобы просто написать:
takeAsParameter(Capture[F])
и
Capture[F] { fa => /* a */ }