gpt4 book ai didi

scala - 使用代数验证和捕获错误

转载 作者:行者123 更新时间:2023-12-04 08:46:53 25 4
gpt4 key购买 nike

我在媒体上看到了这篇文章: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]
}
}
}

以下是我的问题:
  • 鉴于类型是在对象中声明的,scala 编译器如何解决/处理任意类型?它似乎取决于 apply 方法参数类型,但是这与 Capture 是一个对象并且您可以有多个不同类型的 apply 调用这一事实有何关系?我偶然发现了这篇文章What is the meaning of a type declaration without definition in an object?但我仍然不清楚。
  • 根据文章,上面的代码使用了另一个库中的技巧 https://github.com/alexknvl .您能否解释一下这种模式背后的想法是什么?它是干什么用的?我了解作者使用它是为了捕获登录过程中可能发生的多种类型的错误。

  • 谢谢!

    更新:

    第一个问题:

    基于 spec当上限缺失时,假定为 Any。因此,Arbitrary 被视为 Any,但是,它似乎与 Any 不可互换。

    这编译:
    object Test {
    type Arbitrary

    def test(x: Any): Arbitrary = x.asInstanceOf[Arbitrary]
    }

    但是,这不会:
    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

    另请参阅此 scala puzzler .

    最佳答案

    这有点晦涩,但类型别名的合法用法。在规范你can read类型别名可能用于引用一些抽象类型并用作类型约束,建议编译器应该允许什么。

  • type X >: L <: U将意味着 X ,无论它是什么,都应该绑定(bind)在 L 之间和 G - 实际上,我们知道满足该定义的任何值都可以在那里使用,
  • type X = Y是非常精确的约束 - 编译器知道每次我们有 Y 我们都可以称它为 Y,反之亦然
  • 但是 type X也是合法的。我们通常用它来声明它在trait什么的,但是我们在扩展类时对它施加了更多的限制。

    trait TestA { type X }
    trait TestB extends TestA { type X = String }

    但是,我们 不必将其指定为具体类型 .

  • 所以问题中的代码

        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 ?一种方法是使用来自 ~> 的自然变换(或 FunctionKF[_] )至 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]

    该模式的另一部分是排序类型参数的部分应用。如果您一口气完成了一些事情:

    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 */ }
  • 关于scala - 使用代数验证和捕获错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56244808/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com