Merkmal, FunktionN oder Merkmalserben-FunktionN in Scala?

8

Ich habe eine Eigenschaft in Scala, die eine einzige Methode hat. Nennen Sie es berechenbar und die einzige Methode ist compute (Eingabe: Int): Int. Ich kann nicht herausfinden, ob ich

sollte
  • Belassen Sie es als eigenständiges Merkmal mit einer einzigen Methode.
  • Erben von (Int = & gt; Int) und benennen "compute" in "apply" um.
  • Löschen Sie einfach Computable und verwenden Sie (Int = & gt; Int).

Ein Faktor, der dafür spricht, dass es ein Merkmal ist, dass ich einige zusätzliche Methoden hinzufügen könnte. Aber natürlich, wenn sie alle in Bezug auf die Rechenmethode implementiert wären, könnte ich sie einfach in ein separates Objekt aufteilen.

Ein Faktor für die einfache Verwendung des Funktionstyps ist die Einfachheit und die Tatsache, dass die Syntax für eine anonyme Funktion prägnanter ist als für eine anonyme Computable-Instanz. Aber dann habe ich keine Möglichkeit, Objekte, die eigentlich Computable-Instanzen sind, von anderen Funktionen zu unterscheiden, die Int Int zuweisen, aber nicht im selben Kontext wie Computable verwendet werden sollen.

Wie gehen andere Menschen mit dieser Art von Problem um? Keine richtigen oder falschen Antworten hier; Ich suche nur Rat.

    
Willis Blackburn 18.06.2010, 10:13
quelle

4 Antworten

3

Das Erstellen eines Merkmals, das sich von einem Funktionstyp erstreckt, kann aus verschiedenen Gründen nützlich sein.

  1. Ihr Funktionsobjekt macht etwas Spezielles und Nicht-Offensichtliches (und schwer zu schreiben), und Sie können geringfügige Variationen in einem Konstruktor parametrisieren. Angenommen, Sie haben ein Merkmal zum Ausführen einer XPath-Abfrage in einer XML-Struktur geschrieben. Die Anwendungsfunktion würde beim Erstellen des XPath-Abfragemechanismus mehrere Arten von Arbeit verbergen, aber es lohnt sich immer noch, die Function1 -Schnittstelle zu implementieren, so dass Sie ausgehend von einer ganzen Reihe verschiedener Knoten mit map oder flatMap .

  2. Als Erweiterung von # 1 möchten Sie eine Verarbeitung zur Konstruktionszeit durchführen (z. B. den XPath-Ausdruck analysieren und kompilieren, um schnell zu laufen), Sie können das einmal im Konstruktor des Objekts tun ( während, wenn Sie% cc_de% s ohne Unterklasse nur curried, die Kompilierung konnte nur zur Laufzeit passieren, so würde es für jede Abfrage wiederholt werden.)

  3. Sie möchten eine Verschlüsselungsfunktion (eine Art Function ) als implizite, aber nicht alle Function1[String,String] s Verschlüsselung übergeben. Durch Ableiten von Function1[String,String] und Benennen der Unterklasse / des Merkmals Function1[String,String] können Sie sicherstellen, dass nur Funktionen der rechten Unterklasse implizit übergeben werden. (Dies gilt nicht, wenn EncryptionFunction deklariert wird.)

Ich hoffe, das war klar.

    
Ken Bloom 21.06.2010, 02:37
quelle
8

Wenn Sie es zu einer Eigenschaft machen und trotzdem die Syntax der Lightweight-Funktion verwenden möchten, können Sie zusätzlich eine implizite Konvertierung an den Stellen hinzufügen, an denen Sie sie haben möchten:

%Vor%     
Mirko Stocker 18.06.2010 12:28
quelle
1

Es klingt, als ob Sie einen Strukturtyp . Sie werden auch als implizite Schnittstellen bezeichnet.

Sie könnten dann die Methoden umformen, die derzeit eine Computable akzeptieren, um alles zu akzeptieren, das eine Methode compute(input: Int) hat.

    
scompt.com 18.06.2010 10:30
quelle
1

Eine Option besteht darin, einen Typ zu definieren (man kann es immer noch Computable nennen), der im Moment Int = Int int ist. Verwenden Sie es immer, wenn Sie das berechenbare Zeug benötigen. Sie erhalten alle Vorteile, wenn Sie von Funktion1 erben. Wenn Sie feststellen, dass Sie noch weitere Methoden benötigen, können Sie den Typ in ein anderes Merkmal ändern.

Zuerst:

%Vor%

Später:

%Vor%

Ein Nachteil davon ist, dass der von Ihnen definierte Typ nicht wirklich ein neuer Typ ist, eher eine Art Alias. Also, bis Sie es in ein Merkmal ändern, akzeptiert der Compiler noch andere Int = & gt; Int Funktionen. Zumindest können Sie (der Entwickler) unterscheiden. Wenn Sie zu einem Merkmal wechseln (und der Unterschied wird wichtig), wird der Compiler herausfinden, wann Sie ein Computable benötigen, aber ein Int = & gt; Int.

Wenn der Compiler andere Int = & gt; Int -s vom ersten Tag an, dann würde ich empfehlen, ein Merkmal zu verwenden, aber int erweitern Int = & gt; Int. Wenn Sie es aufrufen müssen, hätten Sie immer noch die bequemere Syntax.

Eine andere Option könnte darin bestehen, eine Eigenschaft und ein Companion-Objekt mit einer Apply-Methode zu haben, die Int = & gt; Int und erstellt daraus ein Computable. Dann wäre das Erstellen neuer Computables fast so einfach wie das Schreiben einfacher anonymer Funktionen, aber Sie hätten immer noch die Typüberprüfung (die Sie mit impliziter Konvertierung verlieren würden). Außerdem könnten Sie das Merkmal ohne Probleme mischen (aber dann kann das Anwenden des Begleitobjekts nicht verwendet werden).

    
Sandor Murakozi 18.06.2010 10:57
quelle

Tags und Links