Scalaz 镜头组合

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))
                      ^
任何想法可以让这个工作吗?
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的类型推断限制,您可以在这里阅读答案获取更多信息。


非常感谢。我后来偶然发现了这篇文章,它对理解Scala的局限性也很有帮助: http://pchiusano.blogspot.com/2011/05/making-most-of-scalas-extremely-limited.html - billymillions

6

不幸的是,shapelesslenses 在这种情况下对于类型推断也没有太大的帮助。

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应该能做得更好…敬请期待。

+1,谢谢 - 我想知道你是否找到了在Shapeless中正确进行类型推断的方法,但我没有检查。你能否立即知道为什么(snd compose fst[(Int, Int), Int])可以在两个库中工作,但(snd[Int, Int] compose fst)却不行?这与我最初的期望相反。 - Travis Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接