2011-06-19 19 views
8

He estado jugando con los lenguajes funcionales (F # en particular) y realmente me gusta todo el concepto inmutable. Sin embargo, estoy un poco perdido en cómo se supone que debes representar cosas con estado en los lenguajes funcionales.representan cosas con estado en los idiomas funcionales

Por ejemplo, ¿cómo se podría reescribir lo siguiente en un lenguaje funcional? (Cualquier lenguaje funcional está bien ... sólo hay que envolver mi cabeza alrededor de ella)

class state 
{ 
    int current_time; 
    bool is_completed() { 
     return current_time() - start_time > 30 seconds 
    } 
    double get_progress() { 
     return (current_time() - start_time)/30 seconds 
    } 
    void start() { 
     start_time = current_time(); 
    } 
} 
void main() { 
    state s; 
    s.start(); 
    while(s.is_completed() == false) { 
      print s.get_progress(); 
    } 
    print "finished"; 
} 
+0

Ver también http://stackoverflow.com/questions/5773070/how-are-mutable-arrays-implemented-in-haskell y http://stackoverflow.com/questions/tagged/haskell+monads –

Respuesta

8

Su ejemplo contiene algunas cosas esto funcionaría de manera diferente en un lenguaje funcional:

  • la clase es mutable - en los lenguajes funcionales, se utiliza un tipo inmutable
  • Estás usando current_time para obtener la hora actual, pero esto no es una función pura (depende de algún estado de cambio global). En pure idiomas funcionales (Haskell), esto no está permitido (y debe usar mónadas), pero la mayoría de los lenguajes funcionales impuros (F #, OCaml) lo permiten.
  • Su función main utiliza un bucle: los bucles generalmente se desaconsejan en los lenguajes funcionales (aunque algunos los admiten).

La solución # F idiomática sería tratar con el primer y el último punto de la siguiente manera:

let currentTime() = 
    System.DateTime.Now 

type State(startTime) = 
    static member Start() = 
    State(currentTime()) 
    member x.IsCompleted = 
    (currentTime() - startTime).TotalSeconds > 30.0 
    member x.Progress = 
    (currentTime() - startTime).TotalSeconds/30.0 

let main() = 
    let s = State.Start() 
    let rec loop() = 
    if not s.IsCompleted then 
     printf "%A" s.Progress 
     loop() 
    loop() 
    printf "finished" 

El tipo State es inmutable en el sentido de que nunca cambia el valor de su ámbito local. No es puramente funcional, porque depende de la hora actual (cambiante), pero eso no es un problema en F # (solo tienes que ser consciente de eso).Si necesita algún método que modifique el estado (que no), el método devolverá una nueva instancia de State (al igual que .NET string).

La función main está escrita usando recursion en lugar de un bucle, en este caso, realmente no importa (el bucle también estaría bien en F #). El punto de utilizar una recursión es que podría pasar el estado actual como argumento y usar una nueva instancia al hacer una llamada recursiva (que esencialmente cambia el estado actual durante el cálculo).

8

estoy un poco perdido de cómo se está suponga para representar cosas con estado en lenguajes funcionales.

En última instancia, las computadoras que comúnmente utilizamos son cosas con estado. Los lenguajes de programación tienen que hacer frente a este hecho en algún nivel, o renunciar a algunas de las capacidades de su computadora host.

idiomas

FP frente a este hecho mediante:

  • que le permite escribir funciones que toman estado, y producir nuevo estado (por lo tanto haciendo la función sin estado)
  • Envolver el concepto de estado en un Monad (o en F #, a Computation Expression)

En cuanto a su código, querría ver la primera de estas opciones. Reescribe tus funciones para aceptar la hora actual como argumento.

2

No sé mucho sobre F #, pero por lo que entiendo, está muy cerca de OCaml. Así que aquí hay algunos OCaml:

Los tipos de registros son muy buenos en esto. Aquí hay un código equivalente en OCaml:

#load "unix.cma" ;; 

type state = { start : float } ;; 

let mystate = { start = Unix.time() } in 
    let rec check() = 
     if Unix.time() -. mystate.start > 30. then 
      print_endline "finished" 
     else 
      check() 
    in 
     check() ;; 

(tiempo Unix es un flotador en OCaml por alguna razón, se podía convertir en un int32 si te hace sentir mejor.)

Cuestiones relacionadas