2012-07-08 16 views
9

Desidero definire il sollevamento con impliciti. Supponiamo di avere una funzione A => B, voglio definire come sollevarla a Forse, cioè Forse [A] => Forse [B].Funzioni di sollevamento in scala

Questo può essere fatto semplicemente con conversioni implicite. Tuttavia, se voglio fare lo stesso con le funzioni con due o più parametri, ho un problema. L'unica soluzione che so è duplicare il codice.

Desidero implementare tale sollevamento per funzioni arbitrarie con un numero qualsiasi di parametri senza duplicazione. È possibile in Scala?

+2

Questo potrebbe valere la pena guardare: http://blog.tmorris.net/lifting/ –

+0

Dai un'occhiata a http://www.scala-lang.org/api/current/index.html#scala.Function2 , nota la funzione tupla. Anche http://www.scala-lang.org/api/current/index.html#scala.Function$ metodi tupled e unupupled. – pedrofurla

risposta

18

Se F ha un'istanza di functor disponibile, è possibile sollevare qualsiasi funzione da A => B a F[A] => F[B].

Se F dispone di un'istanza di functor applicativo disponibile, è possibile sollevare qualsiasi funzione da A => B => C => .. => Z a F[A] => F[B] => F[C] => .. => F[Z]. Essenzialmente, il functor applicativo è una generalizzazione del funtore per l'arbitar arbitrario.

È possibile conoscere i funtori funzionali e applicativi here e here. C'è anche il this discorso eccellente che copre queste idee.

La libreria Scalaz fornisce queste astrazioni (e altro ancora!).

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 protettori lift metodo su Function2, Function3 ecc perché funzioni al curry essendo syntactially più pesanti sono usati meno spesso. Dietro le quinte, il sollevamento avviene con Function1 s (cioè funzioni al curry).

Si potrebbe anche voler dare un'occhiata a Scalaz source code.

+1

Stranamente 'foo.lift [Opzione]' non compila con Scalaz 7, ma 'add.lift [Opzione]' fa –

+1

@NikitaVolkov, Fai solo un'ipotesi qui ... 1. 'Functor [Opzione] .lift (foo) 'e' Applicativo [Opzione] .lift2 (aggiungi) 'potrebbe funzionare. Ora ci sono meno "metodi di estensione" all'esterno. 2. La maggior parte dei metodi di estensione sono ancora disponibili in un pacchetto 'scalaz.syntax'. L'ascensore che stai cercando potrebbe trovarsi lì. – missingfaktor

+0

è il codice sopra dovrebbe funzionare su Scalaz 7.1 e Scala 2.11.5? –