Vraag Hoe zou je idioom rekenkundige functies voor andere datatypes in Clojure uitbreiden?


Dus ik wil gebruiken java.awt.Color voor iets, en ik zou graag code als volgt kunnen schrijven:

(use 'java.awt.Color)
(= Color/BLUE (- Color/WHITE Color/RED Color/GREEN))

Kijkend naar de kernimplementatie van -, het spreekt specifiek over clojure.lang.Numbers, wat voor mij impliceert dat er niets is dat ik doe om de kernimplementatie te 'haken' en uit te breiden.

Kijkend rond op het internet, lijken er twee verschillende dingen te zijn die mensen doen:

  • Schrijf ze op defn - functie, die alleen op de hoogte is van het gegevenstype waarin ze geïnteresseerd zijn. Als u dit wilt gebruiken, eindigt u waarschijnlijk vooraf aan een naamruimte, bijvoorbeeld:

    (= Color/BLUE (scdf.color/- Color/WHITE Color/RED Color/GREEN))

    Of anders usede naamruimte en gebruik clojure.core/- wanneer je nummer wiskunde wilt.

  • Codeer een speciaal geval in uw - implementatie die doorgaat naar clojure.core/- wanneer uw implementatie is aangenomen Number.

Helaas vind ik dit beide niet leuk. De eerste is waarschijnlijk de schoonste, omdat de tweede ervan uitgaat dat de enige dingen die je belangrijk vindt om met wiskunde bezig te zijn, hun nieuwe datatype en getallen zijn.

Ik ben nieuw bij Clojure, maar zouden we hier niet in staat moeten zijn om protocollen of multimethoden te gebruiken, zodat wanneer mensen aangepaste typen maken / gebruiken ze deze functies kunnen 'uitbreiden' zodat ze naadloos werken? Is er een reden dat +,- enz. ondersteunt dit niet? (of ze? Ze lijken niet te uit mijn lezen van de code, maar misschien lees ik het verkeerd).

Als ik mijn eigen extensies wil schrijven voor veelgebruikte bestaande functies zoals + voor andere datatypes, hoe moet ik het doen, zodat het goed speelt met bestaande functies en mogelijk andere datatypes?


10
2018-05-12 00:16


oorsprong


antwoorden:


De waarschijnlijke reden om geen rekenkundige bewerking in de kern uit te voeren op basis van protocollen (en ze alleen werk van getallen te maken) is prestatie. Een protocolimplementatie vereist een aanvullende opzoeking voor het kiezen van de juiste implementatie van de gewenste functie. Hoewel het vanuit ontwerpoogpunt leuk kan zijn om protocolgebaseerde implementaties te hebben en deze uit te breiden wanneer dat nodig is, maar wanneer je een strakke lus hebt die deze bewerkingen vaak doet (en dit is heel gebruikelijk bij rekenkundige bewerkingen) zul je beginnen te voelen de prestatieproblemen vanwege de extra opzoeking bij elke bewerking die tijdens runtime plaatsvindt.

Als u een afzonderlijke implementatie heeft voor uw eigen gegevenstypen (bijv: color/-) in hun eigen naamruimte, dan zal het meer performant zijn door een directe oproep naar die functie en het maakt de dingen ook explicieter en aanpasbaarder voor specifieke gevallen.

Een ander probleem met deze functies is hun variadische aard (dat wil zeggen dat ze een willekeurig aantal argumenten kunnen gebruiken). Dit is een serieus probleem bij het leveren van een protocolimplementatie aangezien protocol uitgebreide typecontrole alleen werkt op de eerste parameter.


4
2018-05-12 07:42



Het was hier niet precies voor ontworpen, maar core.matrix kan hier van belang zijn, om een ​​paar redenen:

  • De broncode biedt voorbeelden van het gebruik van protocollen voor het definiëren van bewerkingen die met verschillende typen werken. Bijvoorbeeld, (+ [1 2] [3 4]) => [4 6]). Het is de moeite waard om te bestuderen hoe dit wordt gedaan: in feite zijn de operators reguliere functies die een protocol oproepen, en elk gegevenstype biedt een implementatie van het protocol via extend-protocol
  • Misschien ben je geïnteresseerd in maken java.awt.Color werken als een core.matrix-implementatie (d.w.z. als een 4D RGBA-vector). Ik deed hier iets vergelijkbaars met BufferedImage: https://github.com/clojure-numerics/image-matrix. Als u de basis core.matrix-protocollen implementeert, krijgt u de volledige core.matrix-API om mee te werken Color voorwerpen. Dat bespaart u veel werk bij de uitvoering van verschillende operaties.

5
2018-05-12 02:13



Je kunt er naar kijken algo.generic.arithmetic in algo.generic. Het maakt gebruik van multimethoden.


1
2018-06-11 11:02