【问题标题】:Find type class instance for Shapeless HList in Scalaz state monad在 Scalaz 状态单子中查找 Shapeless HList 的类型类实例
【发布时间】: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, ?, ?] 的函数。我们给出{ _ =&gt; take(_1) },它返回一个IndexedState[S, tk.Out, Unit]。我认为两者之间的匹配应该将S 修复为Int :: String :: HNil。我在这里错过了什么?

标签: scala type-inference scalaz shapeless


【解决方案1】:

以下编译:

for {
  _ <- init[Int :: String :: HNil] flatMap { _  => take(_1) }
  x <- state("abc")
} yield x

您问题的for-loop 大致翻译为

init[Int :: String :: HNil] flatMap { _ =>
  take(_1) flatMap { _ =>
    state("abc") map { x =>
      x
    }
  }
}

而且 scalac 似乎不愿意推断 take(_1) 的类型参数,因为它已经必须推断它下面的一些类型,并且您直接在其上调用 flatMap。

【讨论】:

  • 你知道为什么scalac不愿意推断take(_1)的类型参数吗?我不明白为什么第一个代码 sn-p(结合了序列理解和 flatMap)编译,而第二个(未加糖的)没有!它是一个 scalac 错误吗?
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 2011-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-27
  • 1970-01-01
相关资源
最近更新 更多