2010-07-28 12 views
6

Yo estaba jugando con ListW.<^>, cuya definición es la siguiente:Escriba la pregunta de inferencia utilizando Scalaz.ListW. <^>

def <^>[B: Zero](f: NonEmptyList[A] => B): B = value match { 
    case Nil => ∅ 
    case h :: t => f(Scalaz.nel(h, t)) 
} 

no puedo averiguar cómo es que Option está siendo elegido como el tipo Zero para este ejemplo

scala> case class CC(v : Int) 
defined class CC 

scala> val posns = List(CC(2), CC(5), CC(1)) 
posns: List[CC] = List(CC(2), CC(5), CC(1)) 

Así ahora tengo una lista de estas cosas. Mi objetivo es obtener un Option[CC] para el mínimo/máximo de posns donde obtengo un None por minuto si no hay valores por debajo de cero y similares para máx.

scala> import scalaz._; import Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> implicit val CCOrder = new Order[CC] { 
     | def order(v1 : CC, v2 : CC) = orderBy((v : CC) => v.v).order(v1, v2) 
     | } 
CCOrder: java.lang.Object with scalaz.Order[CC] = [email protected] 

scala> posns.filter(_.v < 0) <^> (_.min) 
res0: Option[CC] = None 

scala> posns.filter(_.v > 0) <^> (_.max) 
res1: Option[CC] = Some(CC(5)) 

opción era exactamente el tipo Zero que quería! ¿Alguien puede explicar cómo el typer ha elegido Option? No lo declaro en cualquier parte!

Respuesta

5

Las definiciones para ListW#<^> y MA#min:

sealed trait MA[M[_], A] extends PimpedType[M[A]] { 
    def min(implicit r: Foldable[M], ord: Order[A]): Option[A] = 
    foldl1((x: A, y: A) => if (x ≨ y) x else y) 
} 

sealed trait ListW[A] extends PimpedType[List[A]] { 
    def <^>[B: Zero](f: NonEmptyList[A] => B): B = value match { 
    case Nil => ∅ 
    case h :: t => f(Scalaz.nel(h, t)) 
    } 
} 

Aquí están los tipos pertinentes inferidos, conversión implícita, y los parámetros implícitos. scalac -Xprint:typer revelará esto.

object test { 
    import scalaz._ 
    import Scalaz._ 

    case class CC(v: Int) 
    val posns = List(CC(2), CC(5), CC(1)) 
    val filtered = posns.filter(((x$1: CC) => x$1.v.<(0))) 
    val listw = Scalaz.ListTo[CC](posns.filter(((x$1: CC) => x$1.v.<(0)))) 
    listw.<^>[Option[CC]]{ 
    (x$2: scalaz.NonEmptyList[CC]) => 
     Scalaz.maImplicit[scalaz.NonEmptyList, CC](x$2).min(Foldable.NonEmptyListFoldable, CCOrder) 
    }(Zero.OptionZero[CC]); 
} 

[email protected]#<^> ejecuta la función proporcionada desde NonEmptyList[A] => B si la lista pimped es no vacía, si no devuelve el Zero para el tipo B. MA#min realmente devuelve Option[B] - es una función general para contenedores, no específica para NonEmptyList, donde podría devolver B.

Una forma más directa de lograr esto es llamar directamente al MA#min. Por desgracia, List ya tiene una función min, nueva en Scala 2.8, por lo que la visión implícita a MA no se desencadena sin una pizca Tipo:

posns.filter(_.v < 0).min 
<console>:16: error: could not find implicit value for parameter cmp: Ordering[CC] 
    posns.filter(_.v < 0).min 

(posns.filter(_.v < 0): MA[List, CC]).min 
res7: Option[CC] = None 

Ésta es una de las razones que motivan a proporcionar identificadores simbólicos en Scalaz - es una forma cruda de espacios de nombres!

Nota al margen: se puede simplificar la instancia de la instancia para OrderCC:

implicit val CCOrder: Order[CC] = orderBy(_.v) 
CCOrder: scalaz.Order[CC] = [email protected] 
+0

Al principio, le dan la definición de 'MA # max' en lugar de' MA # min'. –

+0

Ah. Entonces mi próxima pregunta será: "¿por qué' min' viene de 'MA' y no de' Identity'? " –

+0

@alexey: actualizado. 'x.min (y)' proviene de 'Identity',' xs.min' coincide con 'MA'. – retronym

Cuestiones relacionadas