gpt4 book ai didi

scala - 如何使用 HList 验证输入?

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

我正在使用 Shapeless 2.0 并且我正在尝试使用 HList 来验证输入 - 在编译时执行尽可能多的检查。

我有一个 HList spec它指定了我期望的输入类型(应该在编译时检查类型),还可能包括要执行的运行时检查(例如,测试数字是偶数还是奇数)。

考虑以下规范:

trait Pred[T] { def apply(t: T): Boolean }
val IsString = new Pred[String] { def apply(s: String) = true }
val IsOddNumber = new Pred[Int] { def apply(n: Int) = n % 2 != 0 }
val IsEvenNumber = new Pred[Int] { def apply(n: Int) = n % 2 == 0 }
val spec = IsEvenNumber :: IsString :: IsString :: IsOddNumber :: HNil

以及各种样本输入:
val goodInput = 4 :: "foo" :: "" :: 5 :: HNil
val badInput = 4 :: "foo" :: "" :: 4 :: HNil
val malformedInput = 4 :: 5 :: "" :: 6 :: HNil

我将如何制作一个可以有效执行的功能:
input.zip(spec).forall{case (input, test) => test(input)}

所以会发生以下情况:
f(spec, goodInput) // true
f(spec, badInput) // false
f(spec, malformedInput) // Does not compile

最佳答案

Travis Brown 的这些答案包括大部分需要的内容:

  • https://stackoverflow.com/a/20452151/86485
  • https://stackoverflow.com/a/21005225/86485

  • 但是我花了很长时间才找到这些答案,弄清楚它们是否适用于您的问题,并找出组合和应用它们的细节。

    我认为你的问题增加了值(value),因为它展示了在解决实际问题时如何解决这个问题,即验证输入。我还将尝试通过展示包括演示代码和测试在内的完整解决方案来增加下面的值(value)。

    这是进行检查的通用代码:
    object Checker {
    import shapeless._, poly._, ops.hlist._
    object check extends Poly1 {
    implicit def apply[T] = at[(T, Pred[T])]{
    case (t, pred) => pred(t)
    }
    }
    def apply[L1 <: HList, L2 <: HList, N <: Nat, Z <: HList, M <: HList](input: L1, spec: L2)(
    implicit zipper: Zip.Aux[L1 :: L2 :: HNil, Z],
    mapper: Mapper.Aux[check.type, Z, M],
    length1: Length.Aux[L1, N],
    length2: Length.Aux[L2, N],
    toList: ToList[M, Boolean]) =
    input.zip(spec)
    .map(check)
    .toList
    .forall(Predef.identity)
    }

    这是演示使用代码:
    object Frank {
    import shapeless._, nat._
    def main(args: Array[String]) {
    val IsString = new Pred[String] { def apply(s: String) = true }
    val IsOddNumber = new Pred[Int] { def apply(n: Int) = n % 2 != 0 }
    val IsEvenNumber = new Pred[Int] { def apply(n: Int) = n % 2 == 0 }
    val spec = IsEvenNumber :: IsString :: IsString :: IsOddNumber :: HNil
    val goodInput = 4 :: "foo" :: "" :: 5 :: HNil
    val badInput = 4 :: "foo" :: "" :: 4 :: HNil
    val malformedInput1 = 4 :: 5 :: "" :: 6 :: HNil
    val malformedInput2 = 4 :: "foo" :: "" :: HNil
    val malformedInput3 = 4 :: "foo" :: "" :: 5 :: 6 :: HNil
    println(Checker(goodInput, spec))
    println(Checker(badInput, spec))
    import shapeless.test.illTyped
    illTyped("Checker(malformedInput1, spec)")
    illTyped("Checker(malformedInput2, spec)")
    illTyped("Checker(malformedInput3, spec)")
    }
    }

    /*
    results when run:
    [info] Running Frank
    true
    false
    */

    注意使用 illTyped验证不应该编译的代码,不。

    一些旁注:
  • 我最初带着这个沿着一条长长的花园小路走下去,我认为这对多态函数很重要check具有比 Poly1 更具体的类型, 表示所有情况下的返回类型都是 bool 值。所以我一直试图让它与 extends (Id ~>> Boolean) 一起工作.但事实证明,类型系统是否知道结果类型在每种情况下都是 bool 值并不重要。我们实际拥有的唯一案例具有正确的类型就足够了。 extends Poly1是一件了不起的事情。
  • 值(value)级zip传统上允许不相等的长度并丢弃额外的。迈尔斯效仿Shapeless的类型级别zip ,所以我们需要单独检查相等的长度。
  • 有点遗憾的是,调用站点要import nat._ , 否则为 Length 的隐式实例没有找到。人们更愿意在定义站点处理这些细节。 ( A fix is pending. )
  • 如果我理解正确,我不能使用 Mapped (a la https://stackoverflow.com/a/21005225/86485 )以避免长度检查,因为我的一些跳棋(例如 IsString )具有比例如更具体的单例类型Pred[String] .
  • Travis 指出 Pred可以延长 T => Boolean ,可以使用 ZipApply .我把这个建议留给读者作为练习:-)
  • 关于scala - 如何使用 HList 验证输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22544944/

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