2012-03-08 14 views
6

Sto implementando un framework FRP in Scala e sembra che si sia verificato un problema. Motivato da qualche pensiero, questa domanda ho deciso di limitare l'interfaccia pubblica del mio quadro così Comportamenti potrebbe essere valutata solo nel 'presente' cioè:Implementazione dell'istantanea in FRP

behaviour.at(now) 

Questo rientra anche in linea con assunzione di Conal nella carta Fran che I comportamenti vengono valutati/campionati solo in momenti crescenti. Essa limita le trasformazioni sui comportamenti ma per il resto ci troviamo in enormi problemi con i comportamenti che rappresentano un certo input:

val slider = Stepper(0, sliderChangeEvent) 

Con questo comportamento, valutando i valori futuri sarebbe scorretto e la valutazione di valori passati richiederebbe una quantità illimitata di memoria (tutte le occorrenze utilizzate nell'evento "slider" dovrebbero essere memorizzate).

Ho riscontrato problemi con le specifiche per l'operazione "snapshot" su Behaviors data questa restrizione. Il mio problema è spiegato meglio con un esempio (utilizzando il cursore di cui sopra):

val event = mouseB // an event that occurs when the mouse is pressed 
val sampler = slider.snapshot(event) 
val stepper = Stepper(0, sampler) 

mio problema è che se Event 'mouseB' è verificato quando questo codice viene eseguito quindi il valore corrente di 'stepper' sarà essere l'ultimo 'campione' di 'slider' (il valore al momento in cui si è verificata l'ultima occorrenza). Se il tempo dell'ultima occorrenza è nel passato, di conseguenza, si finirà per valutare il "cursore" utilizzando un tempo passato che infrange la regola impostata sopra (e l'ipotesi originale). Posso vedere un paio di modi per risolvere questo:

  1. Noi 'record' del passato (tenere in mano tutte le occorrenze passate in un evento) che consente la valutazione dei comportamenti con altri tempi (utilizzando una quantità illimitata di memoria)
  2. Modifichiamo 'snapshot' per prendere un argomento di tempo ("campione dopo questa volta") e applicalo ora> = now
  3. In una mossa più stravagante, potremmo limitare la creazione di oggetti FRP alla configurazione iniziale di un programma in qualche modo e solo avviare l'elaborazione di eventi/input dopo questa configurazione è completata

Potrei anche semplicemente non implementare 'sample' o rimuovere 'stepper'/'switcher' (ma non voglio davvero fare nessuna di queste cose). Qualcuno ha qualche pensiero su questo? Ho frainteso qualcosa qui?

+1

Sei a conoscenza di [Reattivo] (http://www.reactive-web.co.cc/), vero? –

+2

Reattivo è bello ma rompe alcune idee in FRP. Ad esempio, non ha una nozione di Behaviors continui: i Segnali in Reattivo cambiano in modo discreto nel tempo tra valori diversi. Inizialmente ero confuso su come questo si adattasse a FRP e ho fatto questa domanda qualche tempo fa: http://stackoverflow.com/questions/7451317/is-the-signal-representation-of-functional-reactive-programming-correct – seadowg

+0

Inoltre, Reattivo in realtà non ha alcuna funzionalità come 'istantanea' per quanto posso dire. – seadowg

risposta

3

Oh capisco cosa intendi ora.

La limitazione "è possibile campionare solo a" ora "" non è abbastanza stretta, penso. Deve essere un po 'più forte per evitare di guardare al passato. Dal momento che stai usando una concezione ambientale di now, definirei le funzioni di costruzione del comportamento in termini di esso (a patto che lo now non possa avanzare con la semplice esecuzione di definizioni, che, per la mia ultima risposta, diventerebbe disordinato). Ad esempio:

Stepper(i,e) è un comportamento con il valore i nell'intervallo [now,e1] (dove e1 è il tempo della prima occorrenza di e dopo now), e il valore più recente insorgenza di e dopo.

Con questa semantica, la tua previsione circa il valore di stepper che ha messo in questa enigma viene smontato, e lo stepper avranno ora il valore 0. Non so se questa semantica è auspicabile per voi, ma mi sembra abbastanza naturale.

+0

Questo è un modo davvero bello di presentarlo. Mi sto solo frustrando nel cercare di trovare un modo per mantenere la semantica originale (adorabile) senza utilizzare una quantità illimitata di memoria. Ho notato che alcune implementazioni rimuovono 'stepper' e 'switcher' a causa di ciò, ma sembrano così dannatamente potenti. Ah bene. – seadowg

+0

@seadowg, la semantica Fran è fantastica, ma finora non siamo riusciti a implementarli in modo efficiente (hanno sempre una perdita di spazio e una corrispondente lentezza). Personalmente ho trascorso circa 6 mesi su questo problema. Inoltre, non siamo in grado di determinare alcun * motivo * per cui sarebbe impossibile, quindi una soluzione potrebbe ancora esistere. Basti dire che non sarà ovvio. – luqui

+1

@luqui: In [questo post del blog] (http://apfelmus.nfshost.com/blog/2012/01/01-frp-api-0-5.html), Heinrich Apfelmus indica [un articolo] (http : //cs.ioc.ee/~tarmo/tsem10/jeltsch-slides.pdf) che presumibilmente fornisce una spiegazione del motivo per cui il tipo di commutazione degli eventi dinamici standard è intrinsecamente sbagliato. Non sono abbastanza esperto per capirlo, ma hai visto questo, e se sì, non lo trovi convincente? (Un po 'fuori tema, lo so, ma ho pensato che sarebbe stato ben noto nella comunità FRP quando l'ho visto.) – ehird

3

Da quello che posso dire, sei preoccupato per una condizione di gara: cosa succede se si verifica un evento mentre il codice è in esecuzione..

Il codice puramente funzionale non vuole sapere che viene eseguito. Le tecniche funzionali sono al loro meglio nell'impostazione pura, così che non importa in quale codice di ordine viene eseguito. Una via d'uscita da questo dilemma è fingere che ogni cambiamento sia avvenuto in un pezzo sensibile (interno, probabilmente) di codice imperativo; fingere che qualsiasi dichiarazione funzionale nel framework FRP si verifichi in 0 volte, quindi è impossibile che qualcosa cambi durante la dichiarazione.

Nessuno dovrebbe mai dormire, o fare davvero qualcosa di sensibile al tempo, in una sezione di codice che è che dichiara comportamenti e cose. Essenzialmente, il codice che funziona con gli oggetti FRP dovrebbe essere puro, quindi non si hanno problemi.

Questo non preclude necessariamente l'esecuzione su più thread, ma per supportare che potrebbe essere necessario riorganizzare le rappresentazioni interne.Benvenuti nel mondo dell'implementazione della libreria FRP - Sospetto che la vostra rappresentazione interna fluttuerà molte volte durante questo processo. :-)

+0

Punto interessante. Non sono preoccupato se qualcosa si verifica mentre questo codice è in esecuzione (tutto ciò potrebbe essere un problema), ma se il mouseB si verifica prima. Semplicemente, data la definizione di 'istantanea', l''ultima' occorrenza nell'evento restituito sarebbe (t, slider.at (t)) dove t seadowg

0

Sono confuso per la tua confusione. Il modo in cui vedo è che Stepper "imposterà" il comportamento su un nuovo valore ogni volta che si verifica l'evento. Quindi, ciò che accade è il seguente:

L'istante in cui si verifica l'evento mouseB, viene letto il valore del comportamento slider (snapshot). Questo valore verrà "impostato" nel comportamento stepper.

Quindi, è vero che lo Stepper "ricorderà" i valori del passato; il punto è che ricorda solo il valore più recente del passato, non tutto.

Semanticamente, è meglio modellare Stepper come una funzione come propone luqui.

+0

Sì, se non stiamo permettendo il campionamento passato. Il mio problema era che se chiamiamo lo snapshot su un comportamento usando un evento che ha occorrenze nel passato, campioneremo questo comportamento usando un tempo passato (che non voglio permettere). Stepper è stato utilizzato per aiutare l'esempio. – seadowg

+0

@seadowg: Ah, capisco. Avete due opzioni: o assicuratevi che, ad un certo punto, il passato fosse nel presente, cioè che abbiate già "passato le occorrenze passate". O devi * tagliare * le occorrenze passate di cui sei appena venuto a conoscenza. Questi sono gli unici modi per evitare perdite di tempo (= ricordare una quantità illimitata di dati del passato). In generale, l'accumulo e la commutazione dinamica degli eventi non possono essere combinati liberamente, devono esserci alcune restrizioni. –