generador etiquetas description f# computation-expression

etiquetas - ¿Por qué las expresiones de cálculo de F#requieren un objeto generador(en lugar de una clase)?



generador de meta description (3)

Es solo una cuestión de flexibilidad. Sí, sería más sencillo si se requiriera que las clases de Builder sean estáticas, pero le quita cierta flexibilidad a los desarrolladores sin ganar mucho en el proceso.

Por ejemplo, supongamos que desea crear un flujo de trabajo para comunicarse con un servidor. En algún lugar del código, deberá especificar la dirección de ese servidor (un Uri, una dirección IP, etc.). ¿En qué casos necesitará / desea comunicarse con múltiples servidores dentro de un único flujo de trabajo? Si la respuesta es ''ninguna'', entonces tiene más sentido para usted crear su objeto constructor con un constructor que le permita pasar la dirección Uri / IP del servidor en lugar de tener que pasar ese valor continuamente a través de varias funciones. Internamente, su objeto generador puede aplicar el valor (la dirección del servidor) a cada método en el flujo de trabajo, creando algo como (pero no exactamente) una mónada Reader.

Con los objetos de constructor basados ​​en instancias, también puede usar la herencia para crear jerarquías de tipos de constructores con alguna funcionalidad heredada. Todavía no he visto a nadie hacer esto en la práctica, pero una vez más, la flexibilidad está ahí en caso de que la gente lo necesite, lo que no tendrías con los objetos de constructor de tipo estático.

Las expresiones de cálculo F # tienen la sintaxis:

ident { cexpr }

Donde ident es el objeto constructor (esta sintaxis se toma de la entrada del blog de Don Syme''s 2007 ).

En todos los ejemplos que he visto, los objetos del constructor son instancias singleton, y sin estado para arrancar. Don da el ejemplo de definir un objeto constructor llamado attempt :

let attempt = new AttemptBuilder()

Mi pregunta: ¿Por qué F # no usa la clase AttemptBuilder directamente en las expresiones de cálculo? Seguramente la notación podría ser desclasificada a llamadas de método estáticas tan fácilmente como llamadas de método de instancia.

El uso de un valor de instancia significa que uno podría, en teoría, crear una instancia de múltiples objetos de constructor de la misma clase, supuestamente parametrizados de alguna manera, o incluso (cielo no permitido) con un estado interno mutable. Pero no puedo imaginar cómo sería útil eso alguna vez.

Actualización: la sintaxis que cité anteriormente sugiere que el constructor debe aparecer como un único identificador, lo que es engañoso y probablemente refleja una versión anterior del idioma. La especificación de lenguaje F # 2.0 más reciente define la sintaxis como:

expr { comp-or-range-expr }

lo que deja en claro que cualquier expresión (que se evalúe como un objeto generador) puede usarse como el primer elemento de la construcción.


Otra alternativa es hacer uso de uniones discriminadas de un solo caso como en:

type WorkFlow = WorkFlow with member __.Bind (m,f) = Option.bind f m member __.Return x = Some x

entonces puedes usarlo directamente como

let x = WorkFlow{ ... }


Tu suposición es correcta; una instancia de constructor se puede parametrizar, y los parámetros se pueden usar posteriormente a lo largo del cálculo.

Utilizo este patrón para construir un árbol de pruebas matemáticas para un cierto cálculo. Cada conclusión es un triple del nombre de un problema , un resultado de cálculo y un árbol N de conclusiones subyacentes (lemas).

Permítanme darles un pequeño ejemplo, eliminando un árbol de prueba, pero conservando el nombre del problema . Llamémosla anotación ya que parece más adecuada.

type AnnotationBuilder(name: string) = // Just ignore an original annotation upon binding member this.Bind<''T> (x, f) = x |> snd |> f member this.Return(a) = name, a let annotated name = new AnnotationBuilder(name) // Use let ultimateAnswer = annotated "Ultimate Question of Life, the Universe, and Everything" { return 42 } let result = annotated "My Favorite number" { // a long computation goes here // and you don''t need to carry the annotation throughout the entire computation let! x = ultimateAnswer return x*10 }