10

这里真的很简单的问题。看完精彩的镜头介绍后:

http://www.youtube.com/watch?v=efv0SQNde5Q

我想我可能会尝试演讲中提到的简单示例之一:

import scalaz.Lens._
fst.andThen(snd).set(((1,2),3),9)

这之后是这个错误

error: type mismatch;
 found   : scalaz.Lens[(Nothing, Nothing),Nothing]
 required: scalaz.Lens[(Nothing, Nothing),C]
Note: Nothing <: C, but class Lens is invariant in type B.
You may wish to define B as +B instead. (SLS 4.5)
              fst.andThen(snd).set(((1,2),3))
                      ^

关于如何完成这项工作的任何想法?

4

2 回答 2

9

您将需要帮助编译器。以下任一项都可以:

(fst andThen snd[Int, Int]).set(((1, 2), 3), 9)

或者:

(fst[(Int, Int), Int] andThen snd).set(((1, 2), 3), 9)

我的猜测是 Edward Kmett 在演讲中掩盖了这个问题,因为它与他的主题并不真正相关——这只是 Scala 类型推断系统的(烦人的)怪癖之一。例如,在 Haskell 中,以下内容会很好:

setL (sndLens . fstLens) 9 ((1, 2), 3)

您可以在此处阅读答案以获取有关 Scala 中类型推断限制的更多信息。

于 2012-08-03T03:23:48.107 回答
6

不幸的是,在这种情况下, shapeless镜片形状并没有更好的类型推断,

scala> import shapeless._ ; import Nat._
import shapeless._
import Nat._

scala> def fst[A, B] = Lens[(A, B)] >> _0
fst: [A, B]=> shapeless.Lens[(A, B),A]

scala> def snd[A, B] = Lens[(A, B)] >> _1
snd: [A, B]=> shapeless.Lens[(A, B),B]

scala> (snd compose fst).set(((1, 2), 3))(9)
<console>:16: error: polymorphic expression cannot be instantiated
  to expected type;
 found   : [A, B]shapeless.Lens[(A, B),A]
 required: shapeless.Lens[?,(?, ?)]
              (snd compose fst).set(((1, 2), 3))(9)

但是,如果我们洒一些类型注释,

scala> (snd compose fst[(Int, Int), Int]).set(((1, 2), 3))(9)
res0: ((Int, Int), Int) = ((1,9),3)

问题的根源,无论是在这里还是在 scalaz.Lens 案例中,都是我们需要的是既是值(以便它们可以组合)又是多态(以便我们可以抽象元组元素类型)的镜头。shapeless 和 scalaz 透镜是值,但不是多态的(至少,没有用处)。

shapeless应该可以做得更好……看这个空间。

于 2012-08-03T08:56:35.310 回答