cos*_*sta 8 scala tagless-final zio
我在以下媒体上看到了这篇文章:https : //medium.com/@odomontois/tagless-unions-in-scala-2-12-55ab0100c2ff。我很难理解其中的一段代码。文章的完整源代码可以在这里找到:https : //github.com/Odomontois/zio-tagless-err。
代码是这样的:
trait Capture[-F[_]] {
def continue[A](k: F[A]): A
}
object Capture {
type Constructors[F[_]] = F[Capture[F]]
type Arbitrary
def apply[F[_]] = new Apply[F]
class Apply[F[_]] {
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]
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的问题:
谢谢!
更新:
第一个问题:
根据规格,如果缺少上限,则假定为“任意”。因此,任意处理被视为任意,但是,它似乎无法与任意互换。
这样编译:
object Test {
type Arbitrary
def test(x: Any): Arbitrary = x.asInstanceOf[Arbitrary]
}
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
object Test {
type Arbitrary
def test(x: Any): Arbitrary = x
}
Error:(58, 35) type mismatch;
found : x.type (with underlying type Any)
required: Test.Arbitrary
def test(x: Any): Arbitrary = x
Run Code Online (Sandbox Code Playgroud)
另请参阅此斯卡拉拼图游戏。
虽然类型别名的合法用法有点晦涩难懂。在规范中,您可以阅读类型别名可能用于引用某些抽象类型并用作类型约束,建议编译器应该允许什么。
type X >: L <: U意味着X,无论它是什么,都应该绑定在L和之间G- 实际上我们知道满足该定义的任何值都可以在那里使用,type X = Y是非常精确的约束 - 编译器知道每次我们有 Y 时我们都可以将其称为 Y,反之亦然type X也是合法的。我们通常使用它来声明它trait或其他东西,但随后我们在扩展类中对其施加更多限制。
trait TestA { type X }
trait TestB extends TestA { type X = String }
Run Code Online (Sandbox Code Playgroud)
但是,我们不必将其指定为具体类型。所以问题中的代码
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]
}
Run Code Online (Sandbox Code Playgroud)
可以理解为:我们有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)
}
Run Code Online (Sandbox Code Playgroud)
然而,它不能,这就是为什么你被迫使用.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 = ...
})
Run Code Online (Sandbox Code Playgroud)
不愉快。问题是,你不能传递诸如多态函数之类的东西(此处[A]: F[A] => A)。您只能使用多态方法传递实例(这是FunctionK有效的)。
因此,我们通过将固定的单态函数传递给A无法实例化的类型 ( Arbitrary) 来解决这个问题,因为没有类型编译器可以证明它匹配Arbitrary。
Capture[F](f: F[Arbitrary] => Arbitrary): Capture[F]
Run Code Online (Sandbox Code Playgroud)
F[A] => A然后,当您学习时,您将迫使编译器认为它是类型A。
f(k.asInstanceOf[F[Arbitrary]]).asInstanceOf[A]
Run Code Online (Sandbox Code Playgroud)
该模式的另一部分是排序类型参数的部分应用。如果你一口气做完一件事:
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]
}
}
Run Code Online (Sandbox Code Playgroud)
Capture.apply例如,作为普通函数传递时,您会遇到一些问题。你必须做类似的事情otherFunction(Capture[F](_))。通过创建Apply“工厂”,我们可以拆分类型参数应用并传递函数F[Arbitrary] => Arbitrary。
长话短说,这一切都是为了让你写:
takeAsParameter(Capture[F])和Capture[F] { fa => /* a */ }| 归档时间: |
|
| 查看次数: |
133 次 |
| 最近记录: |