2015-03-01 17 views
5

Sto lavorando con questo codice:Scala classe caso con la funzione di parametri

case class State[S, +A](run: S => (A, S)) { 
    ...           
    def flatMap[B](f: A => State[S, B]): State[S, B] = State(s => {  
    val (a, s1) = run(s) 
    f(a).run(s1) 
    }) 
    ...           
} 

Questa è un'astrazione per lavorare con lo stato puramente funzionale, dal § 6 di FP in Scala. run è un parametro di funzione che accetta uno stato ed emette una tupla di un valore e il nuovo stato.

La mia domanda è di circa la sintassi s => in questa sezione:

... B] = State(s => { ... 

Questo sembra essere utilizzando il 'costruttore' State (cioè apply) per costruire un nuovo oggetto Stato. Ma cosa rappresenta il s? È uno stato "anonimo", che rappresenta un'istanza di stato? In tal caso, in che modo è diverso da this? O si fa s corrisponde al parametro di ingresso del run cioè il S da:

... (run: S => .... 

E perché dovrei fare uso di un costruttore per una definizione di funzione? Si noti che l'ultimo simbolo della definizione flatMap è un ) non uno }, che sta chiudendo il costruttore State apply.

Questo scenario è un po 'diverso rispetto allo standard scenario

case class Person(name: String) 

, così ho pensato che avrei chiesto ...

risposta

10

La seconda ipotesi è corretta, s corrisponde al parametro di ingresso di run funzione, ovvero S, che rappresenta uno stato effettivo che passa attraverso la catena. Quindi s => {...} è solo una definizione lambda di tipo S => (A, S). Lambda e funzioni in Scala sono first-class citizens (valori), quindi puoi passarli come parametri da tenere all'interno di un altro tipo (incluso un po 'di monade).

Qui la funzione, che produce il nuovo stato grezzo S (e il nuovo risultato A), viene completata (vedere l'operazione return) nello stato monade, che viene implementato come classe di casi. Ne abbiamo bisogno per definire l'operazione flatMap (vedi bind) sulla monade.

Per rendere più chiara la funzione passando come parametro, il codice può essere riscritto per:

case class State[S, +A](run: S => (A, S)) { 
    def flatMap[B](f: A => State[S, B]): State[S, B] = { 
     def newState(s: S) = {  
      val (a, s1) = run(s) 
      f(a).run(s1) 
     } 
     State(newState _) 
    } 
} 

Così, secondo l'monad definition:

  • State[S, +A] è un tipo costruttore che prende due tipi semplici (S e covariante A) e restituisce il tipo monadico State
  • State.apply(run: S => (A, S)) la funzione richiede un piano funzione e ritorna (ascensori in) monadic contenitore State, quindi è un operatore "ritorno" della monade
  • State.flatMap[B](f: A => State[S, B]): State[S, B] una corrispondente all'operatore "legare"

cassa classe viene utilizzata solo per avere esplicito funzione "return" (apply) anziché utilizzare l'operatore new.

+0

Grazie mille @ dk14. È tardi, quindi andrò a preparare bene domani e voterò. È interessante notare che sto guardando [Scalaz State Monad] (https://www.youtube.com/watch?v=Jg3Uv_YWJqI) che mostra questa esatta situazione. Parafrasando il presentatore alle 18:40, la sintassi è una "lambda che prende una S e restituisce un SB, innalzato allo stato". –

+0

Nell'esempio della tua domanda tale sollevamento da tipo semplice a monade (operatore "ritorno") è rappresentato da 'State.apply (run: S => (A, S))'. A proposito, è un video del 2012, il moderno scalaz non accetta il 'S => (A, S)' all'interno di 'State.apply' - lo sta facendo solo in [States.state (f: S => (S, A))] (http://scalaz.github.io/scalaz/scalaz-2.9.1-6.0.2/doc.sxr/scalaz/State.scala.html#40600) metodo, quindi c'è un solo un metodo di "ritorno". – dk14

Problemi correlati