2012-08-03 72 views
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)) 
        ^

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

回答

9

你将需要帮助编译器出一点。下面的任一会做:

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

或:

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

我的猜测是,爱德华Kmett掩盖了这个问题的谈话,因为这不是他的真正相关的主题,它只是一个Scala的类型推断系统的(令人讨厌的)怪癖。在Haskell中,例如,下面的就可以了:

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

您可以阅读有关类型推断的斯卡拉限制的详细信息的答案here

+0

非常感谢。我自从偶然发现这篇文章,这也有助于理解scala的局限性: http://pchiusano.blogspot.com/2011/05/making-most-of-scalas-extremely-limited.html – billymillions 2012-08-03 17:55:38

6

不幸的是shapelesslenses在这种情况下没有更好的状态WRT类型推断,

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案例中,我们需要的是透镜,它们都是值(以便它们可以被合成)和多态(以便我们可以对元组类型进行抽象)。无形和scalaz镜头是价值观,但不是多态(至少没有用)。

无形应该可以做得更好......看这个空间。

+0

+1,谢谢 - 我想知道你是否找到了一种在Shapeless中获得类型推断的方法,但没有检查。你知道为什么'(snd compose fst [(Int,Int),Int])'工作(在两个库中)而不是'(snd [Int,Int] compose fst)'?这与我天真的期望是相反的。 – 2012-08-03 14:38:51