2012-07-08 7 views
9

Ich möchte Heben mit implicits definieren. Angenommen, wir haben eine Funktion A => B, möchte ich definieren, wie man sie auf Maybe anhebt, d. H. Vielleicht [A] => Vielleicht [B].Hubfunktionen in der Scala

Dies kann einfach mit impliziten Konvertierungen durchgeführt werden. Wenn ich jedoch dasselbe mit Funktionen mit zwei oder mehr Parametern machen möchte, habe ich ein Problem. Die einzige Lösung, die ich kenne, ist, den Code zu duplizieren.

Ich möchte solche Aufhebung für beliebige Funktionen mit einer beliebigen Anzahl von Parametern ohne Duplizierung implementieren. Ist das in Scala möglich?

+2

Dies könnte einen Blick wert sein: http://blog.tmorris.net/lifting/ –

+0

Werfen Sie einen Blick auf http://www.scala-lang.org/api/current/index.html#scala.Function2 Beachten Sie die Tupelfunktion. Auch http://www.scala-lang.org/api/current/index.html#scala.Function$ tupled und unuplated Methoden. – pedrofurla

Antwort

18

Wenn F eine Funktorinstanz zur Verfügung hat, ist es möglich, jede Funktion A => B auf F[A] => F[B] zu heben.

Wenn F über eine anwendbare Funktorinstanz verfügt, kann jede Funktion A => B => C => .. => Z auf F[A] => F[B] => F[C] => .. => F[Z] gehoben werden. Im wesentlichen ist der anwendungsbezogene Funktor eine Verallgemeinerung von Funktor für willkürliche Arität.

Sie können über Funktor und anwendungsbezogene Funktoren here und here lernen. Es gibt auch this ausgezeichnete Gespräche, die diese Ideen abdecken.

Scalaz Bibliothek bietet diese Abstraktionen (und mehr!).

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 pimps lift Methode auf Function2, Function3 etc weil curried Funktionen syntactially schwerer weniger häufig verwendet werden. Hinter den Kulissen geschieht das Heben mit Function1 s (d. H. Curry-Funktionen).

Sie können auch einen Blick auf Scalaz source code werfen.

+1

Seltsam genug 'foo.lift [Option]' kompiliert nicht mit Scalaz 7, aber 'add.lift [Option]' tut –

+1

@NikitaVolkov, nur eine Vermutung hier ... 1. 'Functor [Option] .lift (foo) 'und' Applicative [Option] .lift2 (add) 'könnte funktionieren. Es gibt jetzt weniger "Erweiterungsmethoden" im Freien. 2. Die meisten Erweiterungsmethoden sind noch in einem Paket "scalaz.syntax" verfügbar. Der "Lift", nach dem Sie suchen, könnte dort liegen. – missingfaktor

+0

soll der obige Code auf Scalaz 7.1 und Scala 2.11.5 funktionieren? –