【发布时间】:2015-02-23 16:55:39
【问题描述】:
假设我有一个状态单子,状态是 HList,我定义了一个组合子,它采用 HList 的第一个 n 元素:
import scalaz._, Scalaz._
import shapeless._, ops.hlist._, Nat._
def take[S <: HList](n: Nat)(implicit tk: Take[S, n.N]):
IndexedState[S, tk.Out, Unit] = ???
for {
_ <- init[Int :: String :: HNil]
_ <- take(_1)
x <- state("abc")
} yield x
scala 编译器在类型推断期间卡住。它不会推断take 的S 类型参数是Int :: String :: HNil。因此,编译器无法找到参数tk 的隐式值。
[error] could not find implicit value for parameter tk: shapeless.ops.hlist.Take[S,shapeless.Nat._1.N]
[error] _ <- take(_1)
我知道我可以通过简单地公开状态或修复S 来帮助编译器。但我不想!这些额外信息似乎是多余的:
def take[S <: HList](hl: S, n: Nat)(implicit tk: Take[S, n.N]):
IndexedState[S, tk.Out, Unit] = ???
for {
hl <- init[Int :: String :: HNil]
_ <- take(hl, _1) // Redundant
_ <- take[Int :: HNil](_1) // Redundant
x <- state("abc")
} yield x
为什么在第一个代码 sn-p 中,scala 编译器将 S 推断为 Nothing 而不是 Int :: String :: HNil?我想知道是否有可能在不暴露状态或提供类型信息的情况下获得这项工作?
提前致谢!
【问题讨论】:
-
我认为编译器没有足够的信息来推断
S- 它所知道的关于S的所有信息是在范围内必须有一个Take[S, n.N]实例,并且这些实例存在很广泛各种不同的S。你和我都知道预期的返回类型是IndexedReaderWriterStateT[..., S, ...],但是从那里意识到S必须是take的类型参数是一条相当复杂的路径。当您扩展预期类型时会发生什么,例如take(_1): IndexedReaderWriterStateT[...],推断正确吗? -
@Imm - 你确定编译器没有足够的信息来推断
S吗?init[Int :: String :: HNil]给出IndexedState[Int :: String :: HNil, Int :: String :: HNil,Int :: String :: HNil]。如果我们遵循类型,那么flatMap应该采用构造IndexedState[Int :: String :: HNil, ?, ?]的函数。我们给出{ _ => take(_1) },它返回一个IndexedState[S, tk.Out, Unit]。我认为两者之间的匹配应该将S修复为Int :: String :: HNil。我在这里错过了什么?
标签: scala type-inference scalaz shapeless