gpt4 book ai didi

scala - 包含一些 F[_] 的元组/hlist 上的通用变换/折叠/映射

转载 作者:行者123 更新时间:2023-12-01 03:46:35 25 4
gpt4 key购买 nike

我最近问 Map and reduce/fold over HList of scalaz.Validation并得到了关于如何转换 Va[T] 的固定大小元组的一个很好的答案(它是 scalaz.Validation[String, T] 的别名)转换为 scalaz.ValidationNel[String, T] .从那时起,我一直在研究 Shapeless 和类型级编程,以尝试提出一种适用于任何大小的元组的解决方案。

这就是我要开始的:

import scalaz._, Scalaz._, shapeless._, contrib.scalaz._, syntax.std.tuple._

type Va[A] = Validation[String, A]

// only works on pairs of Va[_]
def validate[Ret, In1, In2](params: (Va[In1], Va[In2]))(fn: (In1, In2) => Ret) = {
object toValidationNel extends Poly1 {
implicit def apply[T] = at[Va[T]](_.toValidationNel)
}
traverse(params.productElements)(toValidationNel).map(_.tupled).map(fn.tupled)
}

那么 validate是我这样称呼的助手:
val params = (
postal |> nonEmpty[String]("no postal"),
country |> nonEmpty[String]("no country") >=> isIso2Country("invalid country")
)

validate(params) { (postal, country) => ... }

我开始服用任何 Product而不是一对并将其内容限制为 Va[T] :
// needs to work with a tuple of Va[_] of arbitrary size
def validateGen[P <: Product, F, L <: HList, R](params: P)(block: F)(
implicit
gen: Generic.Aux[P, L],
va: UnaryTCConstraint[L, Va],
fp: FnToProduct.Aux[F, L => R]
) = ???

我确实有这样的感觉,简单地添加约束只能确保输入有效,但对实现函数体没有任何帮助,但我不知道如何去纠正它。
traverse然后开始提示缺少证据,所以我最终得到:
def validateGen[P <: Product, F, L <: HList, R](params: P)(block: F)(
implicit
gen: Generic.Aux[P, L],
va: UnaryTCConstraint[L, Va],
tr: Traverser[L, toValidationNel.type],
fp: FnToProduct.Aux[F, L => R]
) = {
traverse(gen.to(params): HList)(toValidationNel).map(_.tupled).map(block.toProduct)
}

然而,编译器继续提示缺少 Traverser[HList, toValidationNel.type]。隐式参数,即使它在那里。

为了获得 traverse,我需要向编译器提供哪些额外的证据?调用编译?和 UnaryTCConstraint 有关系吗?未以对 traverse 有用的方式声明调用,即不能申请 toValidationNelparams因为它不能证明 params仅包含 Va[_] ?

附言我还找到了 leftReduce Shapeless HList of generic types并尝试使用 foldRight而不是 traverse无济于事;在尝试诊断编译器真正缺乏哪些证据时,错误消息并没有太大帮助。

更新:

根据 lmm 所指出的,我已将类型转换移至 HList ,但是,现在的问题是,而在非通用解决方案中,我可以调用 .map(_.tupled).map(block.toProduct)关于 traverse 的结果打电话,我现在得到:

value map is not a member of shapeless.contrib.scalaz.Out


traverse(params.productElements)(toValidationNel)的结果怎么可能调用而不是通用遍历?

更新 2:

更改 Traverser[...]位到 Traverser.Aux[..., Va[L]]帮助编译器找出预期的遍历结果类型,然而,这只会使 validateGen函数编译成功,但在调用站点产生另一个错误:
[error] could not find implicit value for parameter tr: shapeless.contrib.scalaz.Traverser.Aux[L,toValidationNel.type,Va[L]]
[error] validateGen(params) { (x: String :: String :: HNil) => 3 }
[error] ^

我也感觉到 UnaryTCConstraint完全没有必要——但我对 Shapeless 还是太陌生了,不知道是不是这样。

更新 3:

意识到从遍历器出来的类型不能是 Va[L]因为 L本身已经是 Va[_] 的 hlist , 我已经拆分了 L将参数键入 InOut :
def validateGen[P <: Product, F, In <: HList, Out <: HList, R](params: P)(block: F)(
implicit
gen: Generic.Aux[P, In],
va: UnaryTCConstraint[In, Va], // just for clarity
tr: Traverser.Aux[In, toValidationNel.type, Va[Out]],
fn: FnToProduct.Aux[F, Out => R]
): Va[R] = {
traverse(gen.to(params))(toValidationNel).map(block.toProduct)
}

这编译得很好——我很想知道以前的版本是怎么来的 Va[L]作为返回值(即 Traverser.Aux 的第三个参数)甚至编译 - 但是,在调用站点,我现在得到:

Unspecified value parameters tr, fn

最佳答案

您有一个 Traverser[L, toValidationNel.type]这与 Traverser[HList, toValidationNel.type] 不同(这必须适用于任何 HList - 没有机会)。我不知道你为什么写 gen.to(params): HList ,但这是丢弃类型信息;那不应该是 L 类型吗? ?

这可能只会将问题提高一级;我怀疑你能否得到 Traverser你需要自动。但是您应该能够编写一个隐式方法来提供基于 UnaryTCConstraint 的方法。 ,并且有可能无形已经包含了它,它会正常工作。

更新:

在第一个示例中,编译器知 Prop 体的 Traverser它正在使用的实例,所以它知道 Out 是什么类型是。在 validateGen你对 tr.Out 没有任何限制,因此编译器无法知道它是支持 .map 的类型.如果您知道遍历的输出需要是什么,那么您可能需要一个合适的 Traverser.Aux IE。:

tr: Traverser.Aux[L, toValidationNel.type, Va[L]]

(只是不要问我如何确保类型推断仍然有效)。

我想你可能不想要 .map(_.tupled) , 因为 _已经有一个 HList (我怀疑它在原始 validate 中也是多余的),但我从未使用过 .toProduct之前所以也许你是对的。

更新 2:

是的,这和我最初的怀疑一样。查看 Sequencer 的执行情况我怀疑你是对的, UnaryTCConstraint将被 Traverser 所包含.如果您不使用它,那么没有必要要求它。

我能给出的唯一建议是追逐那些应该提供你隐含意义的电话。例如。 Traverser应该来自 Traverser.mkTraverser .因此,如果您尝试调用 Traverser.mkTraverser[String :: String :: HNil, toValidationNel.type, Va[String] :: Va[String] :: HNil]那么你应该可以看到是找不到Mapper还是Sequencer。然后你可以通过应该发生的隐式调用进行递归,直到你找到一个更简单的情况下应该工作,但不是。

关于scala - 包含一些 F[_] 的元组/hlist 上的通用变换/折叠/映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26487430/

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