2012-08-03 40 views
10

Pregunta realmente simple aquí. Después de ver una excelente introducción a las lentes:Scalaz Lens Composición

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

pensé que podría intentar una de las simples ejemplos tratados en la charla:

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

esto fue seguido por este error

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)) 
        ^

¿Alguna idea sobre cómo hacer que esto funcione?

Respuesta

9

Necesitarás ayudar al compilador un poco. Cualquiera de los siguientes sería hacer:

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

o:

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

Mi conjetura sería que Edward Kmett pasado por alto esta cuestión en la charla porque no es realmente relevante para el asunto de que es sólo una de las (molestas) peculiaridades del sistema de inferencia de tipos de Scala. En Haskell, por ejemplo, la siguiente estaría bien:

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

Usted puede leer las respuestas here para obtener más información acerca de las limitaciones de la inferencia de tipos en Scala.

+0

Muchas gracias. Desde entonces me he tropezado con esta publicación, que también es útil para entender las limitaciones de scala: http://pchiusano.blogspot.com/2011/05/making-most-of-scalas-extremely-limited.html – billymillions

6

Desafortunadamente shapeless 's lenses no están en mucho mejor forma WRT tipo de inferencia en este caso,

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) 

Sin embargo, si nos espolvorear un poco de anotaciones de tipo,

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

La raíz de la problema, tanto aquí como en el caso Scalaz.Lens, es que lo que necesitamos son lentes que sean tanto valores (para que puedan ser compuestos) como polimórficos (de modo que podamos abstraer sobre tipos de elementos de tuplas). las lentes sin forma y scalaz son valores, pero no polimórficos (al menos, no útiles).

sin forma debería ser capaz de hacer mejor ... ver este espacio.

+0

+1, gracias - Me preguntaba si habías encontrado una forma de obtener la inferencia tipo correcta en Shapeless pero no verificaste. ¿Sabes por la parte superior de tu cabeza por qué '(y compose fst [(Int, Int), Int])' funciona (en ambas bibliotecas) pero no '(snd [Int, Int] compone fst)'? Es lo opuesto a lo que ingenuamente esperaba. –