2

Dies ist eher eine theoretische Frage, aber ich denke, es muss einen Weg geben, dies zu tun.Pure Funktioneller Ansatz zum Generieren einer eindeutigen ID

Ich habe JS-Komponenten, für die, wenn sie erstellt werden, müssen sie eine eindeutige ID zu einem HTML-Element zuweisen, eine, die in keiner anderen Komponente verwendet wurde. Das ist ziemlich trivial normalerweise:

let currentId = 0; 
function getNextId() { 
    currentId += 1; 
    return currentId; 
} 

function MyComponent() { 
    this.id = getNextId(); 

    // Code which uses id 
} 

let c1 = new MyComponent(); 
// c1.id === 1 
let c2 = new MyComponent(); 
// c2.id === 2 

Ich frage mich, ob es eine Möglichkeit, diese Art der Sache zu tun, nur reine Funktionen verwenden, wie ich versuche, meinen Kopf um einige erweitern rein funktionalen Ideen zu wickeln. Soweit ich sagen kann, würde es Monaden oder etwas von dieser Vielfalt erfordern, aber ich weiß nicht, wie ich das machen soll.

Vielen Dank!

+6

globaler Zustand wird durch 1), die den Zustand als zusätzliches Argument simuliert alle 2) Zurückgeben des (möglicherweise aktualisierten) Zustands als einen zusätzlichen Rückgabewert und 3) Sicherstellen, dass alle Verbraucher des Zustands richtig sequenziert sind, so dass der aktualisierte Zustand von einer Funktion an die nächste Funktion weitergegeben wird. In Haskell ist dies durch die "State" -Monade gekapselt. – chepner

+0

@chepner Das ist schon fast eine Antwort. – duplode

+0

Hey @chepner! Danke für die Information! Könnten Sie vielleicht eine StackOverflow-Antwort bereitstellen, die diese Idee in der Praxis anhand des oben angegebenen Beispiels zeigt? Wenn Sie es tun und es funktioniert, würde ich gerne die Antwort akzeptieren! –

Antwort

4

In Haskell, könnte man so etwas wie

import Control.Monad.State 

data Component = Component Int String deriving (Show) 

getNextId :: State Int Int 
getNextId = do x <- get 
       put (x + 1) 
       return x 

makeComponent :: String -> State Int Component 
makeComponent name = do x <- getNextId 
         return (Component x name) 

components = evalState (traverse makeComponent ["alice", "bob"]) 0 

main = print $ components 

Das obige Skript schreiben würde Ausgabe

[Component 0 "alice",Component 1 "bob"] 

als jeder "Anruf" zu getNextId würde "return" die nächste Nummer in der Schlange. Die traverse Funktion ist so etwas wie map, aber es stellt sicher, dass der Effekt jeder Monade im Laufe der Anwendung makeComponent auf jeden Wert stattfindet.

This link kann einige Hilfe bei der Anpassung an Javascript bieten.


Der State Typkonstruktor selbst ist nur ein Wrapper um eine Funktion, hier vom Typ Int -> (Int, Int). Die Monad Beispiel für diese Art können Sie vermeiden das Schreiben von Code, der wie folgt aussieht:

getNextID :: Int -> (Int, Int) 
getNextID x = (x, x+1) 

makeComponent :: String -> Int -> (Int, Int) 
makeComponent name x = let (now, then) = getNextID x 
         in (then, Component now name) 

components = let state_0 = 0 
       (state_1, c1) = makeComponent "alice" state_0 
       (state_2, c2) = makeComponent "bob" state_1 
      in [c1, c2] 
+1

Schön gesagt. Für noch mehr Sicherheit kann man ein Modul mit einem 'newtype'-Wrapper um' State Int', 'abgeleitet Monad' schreiben und nur' getNextId, get' und wenig anderes exportieren. Auf diese Weise wird der Benutzer weiter daran gehindert, den Zähler zurückzusetzen, ohne Zugriff auf "Put" zu haben. – chi

-1

Sie Verschlüsse verwenden könnte den Zustand des Zählers wie so zu speichern:

var generateRandom = (function seed(){ 
      var start = 0; 
      return function(){ 
      return start++; 
      } 
     })(); 

Um Zufallszahlen zu erzeugen verwenden Sie einfach gehen:

generateRandom(); //logs 0 
generateRandom(); //logs 1 
generateRandom(); //logs 2 and so on.. 

Obwohl dies scheint, wie Sie eine reine Funktion aufrufen Es ist immer noch ein Hack, würde ich sagen. Ich bin im Grunde die seed() - Funktion einmal, wie Sie in der IIFE sehen können und dann im Grunde die zurückgegebene Funktion in der Variablen generateRandom speichern. Also ist es nicht sozusagen rein funktional.

Aber ich hoffe, es bringt Sie in die richtige Richtung.

+1

Aber ist das nicht irgendwie ein reines nicht Funktion seit generateRandom() gibt ein anderes Ergebnis mit denselben Parametern zurück? –

+0

Ja, Sie haben Recht. 'generateRandom()' gibt jedes Mal einen anderen Wert zurück, aber das soll der Zufallszahlengenerator richtig machen? Ich habe festgestellt, dass Sie eine funktionale Implementierung des Zufallszahlengenerators haben möchten. Die Funktion speichert hier den Zustand intern, der es ermöglicht, an erster Stelle Zufallszahlen zu erzeugen. –

+2

All diese Implementierung ändert den Umfang der veränderbaren Variablen; deshalb beantwortet es die Frage überhaupt nicht (obwohl Sie zumindest davor stehen). – duplode

1

reine Funktion würde bedeuten, Sie Staat nicht mutieren.So wird diese Arbeit:

function idGenerator(fnNext, aInit) { 
    function Gen(value){this.value = value} 
    Gen.prototype.next = function() { 
     return new Gen(fnNext(this.value)); 
    }; 
    return new Gen(aInit); 
} 

const evenGen = idGenerator(function(n){return n+2;}, 2); 
evenGen.value      //==> 2 
const evenGen2 = evenGen.next(); 
evenGen2.value     //==> 4 

const loop = function (seq, acc) { 
    return seq.value > 16 ? 
     acc : 
     loop(seq.next(), seq.value+acc); 
} 
const sumEven = loop(evenGen, 0); 
console.log(sumEven);    //==> 72 

Sie zum Beispiel Sie leicht in changeit müssen, damit Zustand übergeben werden kann:

const seq = idGenerator(function(n){return n+1;}, 1); 

function MyComponent(seq) { 
    this.id = seq.value; 
    this.seq = seq; 

    // Code which uses id 
} 

let c1 = new MyComponent(seq); 
// c1.id === 1 
let c2 = new MyComponent(c1.seq.next()); 
// c2.id === 2 
Verwandte Themen