2012-08-03 11 views
10

Domanda davvero semplice qui. Dopo aver visto un eccellente introduzione alle lenti:Scalaz Lens Composizione

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

ho pensato che avrei potuto tentare una delle semplici esempi trattati nel colloquio:

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

questo è stato seguito da questo errore

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

Qualche idea su come farlo funzionare?

risposta

9

Avrete bisogno di aiutare un po 'il compilatore. Una delle seguenti farebbe:

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

o:

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

La mia ipotesi è che Edward Kmett sorvolata questo problema nel parlare perché non è davvero rilevante per il suo soggetto, è solo uno dei le stranezze (fastidiose) del sistema di inferenza di tipo di Scala. In Haskell, per esempio, il seguente andrebbe bene:

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

È possibile leggere le risposte here per ulteriori informazioni sulle limitazioni di inferenza di tipo a Scala.

+0

Grazie mille. Da allora sono incappato in questo post, che è anche utile per comprendere i limiti dello scala: http://pchiusano.blogspot.com/2011/05/making-most-of-scalas-extremely-limited.html – billymillions

6

Purtroppo shapeless 's lenses non sono molto più in forma tipo wrt inferenza in questo 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) 

Tuttavia, se cospargere alcune annotazioni di tipo,

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

La radice della problema, sia qui che nel caso di scalez.Lens, è che ciò di cui abbiamo bisogno sono obiettivi che sono entrambi valori (in modo che possano essere composti) e polimorfici (in modo che possiamo astrarre su tipi di elementi tuple). le lenti informi e scalaz sono valori, ma non polimorfici (almeno, non utilmente).

senza forma dovrebbe essere in grado di fare meglio ... guardare questo spazio.

+0

+1, grazie Mi stavo chiedendo se avessi trovato un modo per ottenere l'inferenza del tipo in Shapeless ma non controllare. Sapete a priori perché '(snd compose fst [(Int, Int), Int])' funziona (in entrambe le librerie) ma non '(snd [Int, Int] compose fst)'? È l'opposto di quello che mi aspetterei ingenuamente. –