2012-06-07 15 views
9

Estaba intentando convertir un ejemplo de haskell, me encontré antes, en scalaz. El ejemplo original, era la siguiente:Instancia aplicable para una tupla con monoide y función dentro de

("Answer to the ", (*)) <*> ("Ultimate Question of ", 6) <*> ("Life, the Universe, and Everything", 7) 

Lo cual, por lo que yo soy capaz de entender, utiliza this ejemplo.

no consigue convertir en scalaz literalmente:

scala> ("Answer to the ", ((_: Int) * (_: Int)) curried) |@| ("Ultimate Question of ", 6) |@| ("Life, the Universe, and Everything", 7) tupled 
res37: (java.lang.String, (Int => (Int => Int), Int, Int)) = (Answer to the Ultimate Question of Life, the Universe, and Everything,(<function1>,6,7)) 

Aunque, he buscado una instancia, y parece be there (de nuevo, por lo que yo soy capaz de entender).

Entonces, la pregunta es: ¿por qué no funciona así? ¿O qué extrañé/no recibí correctamente?

+1

Este código se envía a la instancia de aplicación para tuplas. Que a su vez usa el monoide 'mappend' para listas (concatenación). Entonces, es la composición de la función del segundo componente de la tupla, con la concatenación de la lista de la primera parte. –

Respuesta

5

El equivalente de Scalaz de Control.Applicative<*> también se llama <*>, aunque confusamente toma sus argumentos en el orden opuesto. Por lo que las siguientes obras:

val times = ((_: Int) * (_: Int)) curried 
val a = "Answer to the " 
val b = "Ultimate Question of " 
val c = "Life, the Universe, and Everything" 

(c, 7) <*> ((b, 6) <*> (a, times)) 

O, como he señalado en respuesta a su comentario, podría utilizar el siguiente si quiere seguir con |@|:

(a -> times |@| b -> 6 |@| c -> 7)(_ apply _ apply _) 

yo personalmente prefiero el <*> versión, incluso si se siente hacia atrás.


Podemos ver lo que está pasando con un poco más de detalle. En primer lugar, no necesita la potencia total de Applicative aquí; Apply lo hará. Podemos obtener la instancia Apply tuplas usando implicitly:

scala> val ai = implicitly[Apply[({type λ[α]=(String, α)})#λ]] 
ai: scalaz.Apply[[α](java.lang.String, α)] = [email protected] 

Ahora podemos aplicar nuestra primera tupla a la segunda:

scala> :t ai(a -> times, b -> 6) 
(java.lang.String, Int => Int) 

Y el resultado a la tercera:

scala> :t ai(ai(a -> times, b -> 6), c -> 7) 
(java.lang.String, Int) 

Que es lo que queremos:

scala> ai(ai(a -> times, b -> 6), c -> 7)._1 
res0: java.lang.String = Answer to the Ultimate Question of Life, the Universe, and Everything 

scala> ai(ai(a -> times, b -> 6), c -> 7)._2 
res1: Int = 42 

El método <*> en MA simplemente lo envuelve un poco más.

+0

Gracias, funciona como se supone que debe hacerlo. Por cierto, ¿tienes alguna idea de cómo hacer esto con el ApplicativeBuilder y si se verá mejor así? – folone

+1

Claro, podrías hacer algo como '(a -> times | @ | b -> 6 | @ | c -> 7) (_ apply _ apply _)', pero creo que la versión '<*>' es más bonita. –

+0

Sí, esto funciona. Fui engañado por el hecho de que "tupled" pegó el monoide, así que pensé, aplicaría la función también. – folone

Cuestiones relacionadas