2011-10-03 13 views
5

Dada una firma como éste o that one:cadena visto como un Monoid

def foo[A, F[_]](implicit mon: Monoid[F[A]], pr: Pure[F]): F[A] 

Suponiendo A es Char, ¿hay una manera de conseguir un String en lugar de un List[Char]?

String no toma un parámetro de tipo, así que supongo que no es posible. ¿Cuál es la siguiente mejor opción? En este momento, uso mkString en el resultado, pero eso no parece óptimo.

Creo String es un monoide con cero "" y anexar ... +

+0

¿Por qué necesita Monoid [F [A]] en lugar de solo Monoid [F]? – CheatEx

+0

@CheatEx, en este caso, yo no soy el que escribió 'foo', solo soy el que llama. – huynhjl

Respuesta

7

Es posible convencer a String de hacerse pasar por un tipo de mayor nivel y, por lo tanto, permitir que funciones de la forma foo sean aplicables. Sin embargo, la inferencia de tipos de Scala no está en altura de la tarea de inferir foo 's argumentos de tipo, por lo que tendrá que suministrar de forma explícita,

// Assuming the the definitions of Pure and Monoid from Scalaz 

type ConstString = { 
    type λ[X] = String 
} 

implicit def StringPure = new Pure[ConstString#λ] { 
    def pure[A](a: => A) = a.toString 
} 

val sm = implicitly[Monoid[String]] 
val sp = implicitly[Pure[ConstString#λ]] 
val f : String = foo[Char, ConstString#λ](sm, sp) // OK 

Tenga en cuenta que el tipo de argumento a Charfoo no se utiliza y puede ser cualquier cosa, pero debe ser algo: en este caso, ya sea Char es la elección natural, pero Nothing o Any también lo haría.

en cuenta que esta solución en comercios características especiales String 's: valores de todos los tipos son convertibles a String es tan pure[A](a : => A) : String es implementable para todo tipo A. Replicar este idioma para tipos distintos de String probablemente tendría que explotar algún mecanismo para implementar casos específicos de tipo en el cuerpo de pure (por ejemplo, una coincidencia de patrón de algún tipo).

+2

Pero 'implícitamente [Pure [ConstString # λ]]. Pure ('a')' devolverá la cadena vacía, por lo que no es muy útil. ¿Lo es? –

+0

Claro, necesitaría una definición diferente de 'Pure [ConstString # λ]' para hacer cualquier trabajo útil. Respuesta editada para reflejar eso. –

+0

¡Creo que vi un Kestrel! –

0

Su análisis, que tipo de sistema de Scala rechazará String como no ser un "tipo superior kinded" * -> * es correcto. Es decir, el tipo String no se puede ceder a F[_] para cualquier F. Se podría tratar (No he comprobado esto) conversiones implícitas ...

def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], FA_Is_That: F[A] <%< That) 

... pero esto no será tan útil me sospechoso porque tendrías que proporcionar tus propias conversiones personalizadas cuando sea necesario pero también porque el rendimiento sería terrible, suponiendo que esta sea una parte candente del código.

O, usando la biblioteca estándar, se puede utilizar la maquinaria CanBuildFrom pero está lejos de ser evidente cómo bien esto va a mezclar con las clases de tipos de estilo scalaz.

def foo[A, F[_], That](implicit mon: Monoid[F[A]], pr: Pure[F], b: CanBuildFrom[A, F[A], That]): That 

En el cuerpo del método, por supuesto, usted tendrá que utilizar el constructor para construir el valor de retorno, en contraposición a las clases de tipos monoid/puro, haciéndolos algo redundante, sospecho.

6

La mejor solución que se me ocurre es definir una conversión implícita de List[Char] a String.

Cuestiones relacionadas