scala programacion - ¿Cómo puede existir una función de tiempo en la programación funcional?




java ejemplos (12)

Tengo que admitir que no sé mucho sobre programación funcional. Lo leí de aquí y de allí, y así llegué a saber que en la programación funcional, una función devuelve la misma salida, para la misma entrada, sin importar cuántas veces se llame la función. Es exactamente como una función matemática que evalúa la misma salida para el mismo valor de los parámetros de entrada que implica la expresión de la función.

Por ejemplo, considera esto:

f(x,y) = x*x + y; // It is a mathematical function

No importa cuántas veces uses f(10,4) , su valor siempre será 104 . Como tal, siempre que hayas escrito f(10,4) , puedes reemplazarlo por 104 , sin alterar el valor de la expresión completa. Esta propiedad se conoce como transparencia referencial de una expresión.

Como dice la Wikipedia ( link ),

A la inversa, en el código funcional, el valor de salida de una función depende solo de los argumentos que se ingresan a la función, por lo que llamar a una función f dos veces con el mismo valor para un argumento x producirá el mismo resultado f (x) en ambas ocasiones.

¿Puede existir una función de tiempo (que devuelve el tiempo actual ) en la programación funcional?

  • Si es así, ¿cómo puede existir? ¿No viola el principio de programación funcional? Viola particularmente la transparencia referencial, que es una de las propiedades de la programación funcional (si la comprendo correctamente).

  • O si no, entonces ¿cómo se puede saber la hora actual en la programación funcional?


Answers

Sí, puede existir una función de obtención de tiempo en la programación funcional utilizando una versión ligeramente modificada en la programación funcional conocida como programación funcional impura (la predeterminada o la principal es la programación funcional pura).

En caso de obtener el tiempo (o leer un archivo, o lanzar un misil), el código debe interactuar con el mundo exterior para realizar el trabajo y este mundo exterior no se basa en los fundamentos puros de la programación funcional. Para permitir que un mundo de programación funcional puro interactúe con este mundo exterior impuro, las personas han introducido programación funcional impura. Después de todo, el software que no interactúa con el mundo exterior no es más útil que hacer algunos cálculos matemáticos.

Pocos lenguajes de programación de programación funcional tienen incorporada esta característica de impureza, por lo que no es fácil separar qué código es impuro y cuál es puro (como F #, etc.) y algunos lenguajes de programación funcionales se aseguran de que al hacer algunas cosas impuras ese código es claramente destacado en comparación con el código puro, como Haskell.

Otra forma interesante de ver esto sería que su función de obtención de tiempo en la programación funcional tomaría un objeto de "mundo" que tiene el estado actual del mundo, como el tiempo, el número de personas que viven en el mundo, etc. El objeto siempre será puro, es decir, si pasa en el mismo estado mundial, siempre obtendrá el mismo tiempo.


"Hora actual" no es una función. Es un parámetro. Si su código depende de la hora actual, significa que su código está parametrizado por tiempo.


Si es así, ¿cómo puede existir? ¿No viola el principio de programación funcional? Viola especialmente la transparencia referencial.

No existe en un sentido puramente funcional.

O si no, entonces ¿cómo se puede saber la hora actual en la programación funcional?

Primero puede ser útil saber cómo se recupera una hora en una computadora. Esencialmente, hay circuitos integrados que realizan un seguimiento del tiempo (razón por la cual una computadora usualmente necesita una batería de celda pequeña). Entonces podría haber algún proceso interno que establezca el valor del tiempo en un determinado registro de memoria. Lo que esencialmente se reduce a un valor que puede ser recuperado por la CPU.

Para Haskell, hay un concepto de 'acción de IO' que representa un tipo que se puede hacer para llevar a cabo algún proceso de IO. Entonces, en lugar de hacer referencia a un valor de time , hacemos referencia a un valor de IO Time Todo esto sería puramente funcional. No estamos haciendo referencia al time sino a algo como "leer el valor del registro de tiempo" .

Cuando realmente ejecutamos el programa Haskell, la acción IO realmente tendría lugar.


Me sorprende que ninguna de las respuestas o comentarios mencionen coalgebras o coinduction. Por lo general, la coinducción se menciona al razonar sobre estructuras de datos infinitas, pero también es aplicable a un sinfín de observaciones, como un registro de tiempo en una CPU. Un coalgebra modela el estado oculto; y modelos de coinducción observando ese estado. (Modelos de inducción normal construyendo estado.)

Este es un tema candente en la programación funcional reactiva. Si estás interesado en este tipo de cosas, lee esto: http://digitalcommons.ohsu.edu/csetech/91/ (28 pp.)


Absolutamente se puede hacer de una manera puramente funcional. Hay varias formas de hacerlo, pero la más simple es hacer que la función de tiempo devuelva no solo el tiempo, sino también la función a la que debe llamar para obtener la siguiente medición de tiempo .

En C # podrías implementarlo así:

// Exposes mutable time as immutable time (poorly, to illustrate by example)
// Although the insides are mutable, the exposed surface is immutable.
public class ClockStamp {
    public static readonly ClockStamp ProgramStartTime = new ClockStamp();
    public readonly DateTime Time;
    private ClockStamp _next;

    private ClockStamp() {
        this.Time = DateTime.Now;
    }
    public ClockStamp NextMeasurement() {
        if (this._next == null) this._next = new ClockStamp();
        return this._next;
    }
}

(Tenga en cuenta que este es un ejemplo destinado a ser simple, no práctico. En particular, los nodos de la lista no pueden recogerse como basura porque están arraigados por ProgramStartTime).

Esta clase 'ClockStamp' actúa como una lista enlazada inmutable, pero en realidad los nodos se generan a pedido para que puedan contener el tiempo 'actual'. Cualquier función que quiera medir la hora debe tener un parámetro 'clockStamp' y también debe devolver su última medición de tiempo en su resultado (para que la persona que llama no vea las mediciones anteriores), como esto:

// Immutable. A result accompanied by a clockstamp
public struct TimeStampedValue<T> {
    public readonly ClockStamp Time;
    public readonly T Value;
    public TimeStampedValue(ClockStamp time, T value) {
        this.Time = time;
        this.Value = value;
    }
}

// Times an empty loop.
public static TimeStampedValue<TimeSpan> TimeALoop(ClockStamp lastMeasurement) {
    var start = lastMeasurement.NextMeasurement();
    for (var i = 0; i < 10000000; i++) {
    }
    var end = start.NextMeasurement();
    var duration = end.Time - start.Time;
    return new TimeStampedValue<TimeSpan>(end, duration);
}

public static void Main(String[] args) {
    var clock = ClockStamp.ProgramStartTime;
    var r = TimeALoop(clock);
    var duration = r.Value; //the result
    clock = r.Time; //must now use returned clock, to avoid seeing old measurements
}

Por supuesto, es un poco incómodo tener que pasar esa última medición dentro y fuera, dentro y fuera, dentro y fuera. Hay muchas formas de ocultar la placa, especialmente en el nivel de diseño del idioma. Creo que Haskell usa este tipo de truco y luego oculta las partes feas usando mónadas.


¡Sí! ¡Estás en lo correcto! Now () o CurrentTime () o cualquier firma de método de tal sabor no está mostrando transparencia referencial de una manera. Pero por instrucciones para el compilador está parametrizado por una entrada de reloj del sistema.

Por salida, Ahora () puede parecer que no se sigue la transparencia referencial. Pero el comportamiento real del reloj del sistema y la función que se encuentra encima se adhiere a la transparencia referencial.


La mayoría de los lenguajes de programación funcionales no son puros, es decir, permiten que las funciones no solo dependan de sus valores. En esos idiomas es perfectamente posible tener una función que devuelva la hora actual. De los idiomas con los que marcó esta pregunta, esto se aplica a Scala y F# (así como a la mayoría de las otras variantes de ML ).

En lenguajes como Haskell y Clean , que son puros, la situación es diferente. En Haskell, la hora actual no estaría disponible a través de una función, sino de una acción llamada IO, que es la forma en que Haskell encapsula los efectos secundarios.

En Limpiar sería una función, pero la función tomaría un valor mundial como argumento y devolvería un valor mundial nuevo (además del tiempo actual) como su resultado. El sistema de tipos se aseguraría de que cada valor mundial se pueda usar una sola vez (y cada función que consuma un valor mundial produciría una nueva). De esta manera, la función de tiempo tendría que llamarse con un argumento diferente cada vez y, por lo tanto, se le permitiría devolver un tiempo diferente cada vez.


En Haskell uno usa una construcción llamada mónada para manejar los efectos secundarios. Una mónada básicamente significa que encapsula valores en un contenedor y tiene algunas funciones para encadenar funciones de valores a valores dentro de un contenedor. Si nuestro contenedor tiene el tipo:

data IO a = IO (RealWorld -> (a,RealWorld))

Podemos implementar de forma segura las acciones de IO. Este tipo significa: una acción de tipo IO es una función, que toma un token de tipo RealWorld y devuelve un token nuevo, junto con un resultado.

La idea detrás de esto es que cada acción IO muta el estado externo, representado por el token mágico RealWorld . Mediante el uso de mónadas, se pueden encadenar múltiples funciones que mutan el mundo real. La función más importante de una mónada es >>= , se pronuncia bind :

(>>=) :: IO a -> (a -> IO b) -> IO b

>>= toma una acción y una función que toma el resultado de esta acción y crea una nueva acción a partir de esto. El tipo de retorno es la nueva acción. Por ejemplo, supongamos que hay una función now :: IO String , que devuelve una cadena que representa la hora actual. Podemos encadenarlo con la función putStrLn para imprimirlo:

now >>= putStrLn

O escrito en do -Notation, que es más familiar para un programador imperativo:

do currTime <- now
   putStrLn currTime

Todo esto es puro, ya que mapeamos la mutación y la información sobre el mundo exterior en el token de RealWorld . Entonces, cada vez que ejecuta esta acción, obtiene, por supuesto, una salida diferente, pero la entrada no es la misma: el token de RealWorld es diferente.


Si y no.

Diferentes lenguajes de programación funcionales los resuelven de manera diferente.

En Haskell (uno muy puro) todo esto tiene que suceder en algo que se llama la Mónada de E / S , consulte here .

Puede pensar que es obtener otra entrada (y salida) en su función (el estado del mundo) o más fácil como un lugar donde ocurre la "impureza", como el cambio de tiempo.

Otros lenguajes como F # solo tienen algo de impureza incorporado, por lo que puede tener una función que devuelve diferentes valores para la misma entrada, al igual que los lenguajes imperativos normales .

Como Jeffrey Burka mencionó en su comentario: Aquí está la buena introducción a la E / S Monad directamente desde el wiki de Haskell.


Sí, es posible que una función pura devuelva el tiempo, si se le da ese tiempo como parámetro. Argumento de tiempo diferente, resultado de tiempo diferente. Luego forme otras funciones del tiempo también y combínelas con un vocabulario simple de funciones de función (-t-time) -transforming (orden superior). Dado que el enfoque no tiene estado, el tiempo aquí puede ser continuo (independiente de la resolución) en lugar de discreto, lo que aumenta enormemente la modularidad . Esta intuición es la base de la Programación reactiva funcional (FRP).


Otra forma de explicarlo es esta: ninguna función puede obtener la hora actual (ya que sigue cambiando), pero una acción puede obtener la hora actual. Digamos que getClockTime es una constante (o una función nula, si lo desea) que representa la acción de obtener la hora actual. Esta acción es la misma cada vez que se usa, por lo que es una constante real.

Del mismo modo, digamos que print es una función que toma algún tiempo de representación y la imprime en la consola. Dado que las llamadas a funciones no pueden tener efectos secundarios en un lenguaje funcional puro, en cambio imaginamos que es una función que toma una marca de tiempo y devuelve la acción de imprimirla a la consola. Nuevamente, esta es una función real, porque si le asignas la misma marca de tiempo, devolverá la misma acción de imprimirla cada vez.

Ahora, ¿cómo puedes imprimir la hora actual en la consola? Bueno, tienes que combinar las dos acciones. Entonces, ¿cómo podemos hacer eso? No podemos simplemente pasar getClockTime para print , ya que la impresión espera una marca de tiempo, no una acción. Pero podemos imaginar que hay un operador, >>= , que combina dos acciones, una que obtiene una marca de hora y otra que toma una como argumento y la imprime. Aplicando esto a las acciones mencionadas anteriormente, el resultado es ... tadaaa ... una nueva acción que obtiene la hora actual y la imprime. Y esto es, por cierto, exactamente como se hace en Haskell.

Prelude> System.Time.getClockTime >>= print
Fri Sep  2 01:13:23 東京 (標準時) 2011

Entonces, conceptualmente, puede verlo de esta manera: un programa funcional puro no realiza ninguna E / S, define una acción , que luego ejecuta el sistema de tiempo de ejecución. La acción es la misma cada vez, pero el resultado de su ejecución depende de las circunstancias en que se ejecuta.

No sé si esto fue más claro que las otras explicaciones, pero a veces me ayuda a pensar de esta manera.


implicit class RichAny[A](private val a: A) extends AnyVal {
  @inline
  def match_ignoring_nonexhaustive[B](f: PartialFunction[A,B]): B = f(a)
}

Con esto podría hacer lo siguiente, que en realidad solo interpreta la coincidencia de casos como PartialFunction:

l.sliding(2).foreach{ _ match_ignoring_nonexhaustive {case List(a,b) => }}






scala haskell f# functional-programming clean-language