2016-08-17 2 views
3

Nehmen wir an, ich def haben, die mehrere Parameter des Typs nimmt:In Scala, ist es möglich, "curry" -Typ Parameter eines def?

def foo[A, B, C](b: B, c: C)(implicit ev: Writer[A])

Allerdings ist die beabsichtigte Verwendung, dass Typ-Parameter B und C sollte (auf der Basis der übergebenen in Argumenten) abgeleitet werden. Und der Aufrufer sollte nur explizit A spezifizieren müssen (z. B. um eine implizite Wahlmöglichkeit durch den Compiler zu haben). Leider erlaubt Scala nur, dass alle oder keine der Typparameter vom Aufrufer spezifiziert werden. In gewissem Sinne möchte ich die Typparameter curried werden:

def foo[A][B, C]...

Gibt es einen Trick, um dies in Scala zu erreichen?

(Wenn mein konkretes Beispiel nicht macht durchaus Sinn, ich bin froh, dass es mit Vorschlägen zu verbessern.)

Antwort

5

Die beste Weise, die ich in der Lage habe dies eine Klasse definieren, die das ist, ziehen Sie hält Curry-Typ-Informationen verwenden dann die apply-Methode, um den Funktionsaufruf zu simulieren.

habe ich diese hier geschrieben über - http://caryrobbins.com/dev/scala-type-curry/

Für Ihr spezielles Beispiel, würden Sie die implicit ev: Writes[A] in der Signatur für die apply und nicht in der Signatur für foo setzen müssen. Dies liegt daran, dass es Unklarheiten zwischen der expliziten Übergabe des impliziten Arguments oder dem impliziten Aufrufen der apply-Methode verursacht.

Hier ist ein Beispiel-Implementierung für Ihr Beispiel -

object Example { 
    def foo[A]: _Foo[A] = _foo.asInstanceOf[_Foo[A]] 

    final class _Foo[A] private[Example] { 
    def apply[B, C](b: B, c: C)(implicit ev: Writes[A]): Unit = ??? 
    } 

    private lazy val _foo = new _Foo[Nothing] 
} 

Sie können dann Ihre Art Parameter liefern Sie möchten Curry und die folgenden Argumente an die apply Methode übergeben wird gefolgert werden.

Example.foo[Int]("bar", new Object) 

Wenn Sie am Ende brauchen, um die anderen Parameter des Typs angeben, können Sie dies tun, indem explizit apply Aufruf; obwohl ich noch nie eine Notwendigkeit gesehen habe, dies zu tun.

Example.foo[Int].apply[String, Object]("bar", new Object) 

Wenn Sie nicht möchten, dass die Zwischentyp verwenden Sie auch einen Strukturtyp verwenden können, die ich in dem oben genannten Beitrag zu erörtern; Dies erfordert jedoch reflectiveCalls und eine abgeleitete Signatur, die ich beide vermeiden möchte.

+1

Sehr gut geschrieben und sehr clever! – Alec

Verwandte Themen