2012-07-08 14 views
9

Quiero definir la elevación con implicits. Supongamos que tenemos una función A => B, quiero definir cómo levantarla a Quizás, es decir, Tal vez [A] => Tal vez [B].Funciones de elevación en scala

Esto se puede hacer simplemente con conversiones implícitas. Sin embargo, si quiero hacer lo mismo con funciones con dos o más parámetros, tengo un problema. La única solución que sé es duplicar el código.

Quiero implementar dicho levantamiento para funciones arbitrarias con cualquier cantidad de parámetros sin duplicación. ¿Es esto posible en Scala?

+2

Puede valer la pena visitar: http://blog.tmorris.net/lifting/ –

+0

Eche un vistazo a http://www.scala-lang.org/api/current/index.html#scala.Function2 , observe la función tupled. También http://www.scala-lang.org/api/current/index.html#scala.Function$ métodos agrupados y no desarrollados. – pedrofurla

Respuesta

18

Si F tiene una instancia de functor disponible, es posible levantar cualquier función A => B a F[A] => F[B].

Si F tiene una instancia de aplicador de aplicación disponible, es posible levantar cualquier función A => B => C => .. => Z a F[A] => F[B] => F[C] => .. => F[Z]. Básicamente, el functor aplicativo es una generalización de functor para arity arbitrario.

Puede obtener más información sobre el functor y los funtores aplicativos here y here. También hay this excelente charla que cubre estas ideas.

La biblioteca de Scalaz proporciona estas abstracciones (¡y más!).

import scalaz._ 
import Scalaz._ 

scala> val foo: Int => String = _.toString 
foo: Int => String = <function1> 

scala> foo.lift[Option] 
res0: Option[Int] => Option[String] = <function1> 

scala> res0(Some(3)) 
res1: Option[String] = Some(3) 

scala> res0(None) 
res2: Option[String] = None 

scala> val add: (Int, Int) => Int = _ + _ 
add: (Int, Int) => Int = <function2> 

scala> add.lift[Option] 
res3: (Option[Int], Option[Int]) => Option[Int] = <function2> 

scala> res3(Some(2), Some(1)) 
res4: Option[Int] = Some(3) 

scala> res3(Some(2), None) 
res5: Option[Int] = None 

scala> res3(None, None) 
res6: Option[Int] = None 

Scalaz proxenetas lift método en Function2, Function3 etc porque las funciones curry siendo syntactially más pesado se utilizan con menos frecuencia. Detrás de escena, el levantamiento ocurre con Function1 s (es decir, funciones con curry).

Es posible que también desee echar un vistazo a Scalaz source code.

+1

Por extraño que parezca 'foo.lift [Option]' no se compila con Scalaz 7, pero 'add.lift [Option]' hace –

+1

@NikitaVolkov, solo adivinando aquí ... 1. 'Functor [Option] .lift (foo) 'y' Applicative [Option] .lift2 (add) 'podría funcionar. Ahora hay menos "métodos de extensión" abiertos. 2. La mayoría de los métodos de extensión todavía están disponibles en un paquete 'scalaz.syntax'. El "ascensor" que está buscando podría estar allí. – missingfaktor

+0

¿se supone que el código anterior funciona en Scalaz 7.1 y Scala 2.11.5? –