venta solicitud que punto por para monotributistas imprimir factuweb factura constancia cai cada afip actividad haskell coding-style refactoring pointfree

haskell - solicitud - ¿Es el código de punto libre más eficiente, o simplemente terser?



que es el punto de venta afip (2)

Escribí el siguiente código, que toma un montón de puntos y los dibuja en la pantalla usando la biblioteca de brillo.

let s = blocks pes pts = map (map mkPt) s {- stitches to points-} lines = map Line pts {-points to lines -} pict = Pictures lines {- lines to a picture -} in do displayInWindow "My Window" (200, 200) (10, 10) white pict

Funciona bien, pero se me ocurre que hay un patrón repetido: una cadena de llamadas a funciones, el resultado de cada una alimentando el último argumento del siguiente. Así que lo reformulé eliminando las variables intermedias, invirtiendo el orden y encadenando las funciones con la composición de la función (".") De esta manera:

let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes in do displayInWindow "My Window" (200, 200) (10, 10) white pict

Afortunadamente, esto también funciona bien. Pero me pregunto si estoy restringiendo la legibilidad, o si simplemente no estoy acostumbrado a leer y escribir código de estilo de punto libre. Además, ¿cómo razonar sobre este código? ¿Es la segunda versión más eficiente, o simplemente terser? ¿Hay algo que pueda hacer estilísticamente para hacerlo más claro?


Algunas sugerencias rápidas:

let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes in do displayInWindow "My Window" (200, 200) (10, 10) white pict

Tienes algunas cosas superfluas que pueden eliminarse directamente:

let pict = Pictures . map Line . (map $ map mkPt) . blocks $ pes in do displayInWindow "My Window" (200, 200) (10, 10) white pict

De todos modos, no está evitando los paréntesis con el término map (map mkPt) , así que deshágase de los $ :

let pict = Pictures . map Line . map (map mkPt) . blocks $ pes in do displayInWindow "My Window" (200, 200) (10, 10) white pict

Puede escribir la cadena de composición en varias líneas para mayor claridad:

let pict = Pictures . map Line . map (map mkPt) . blocks $ pes in do displayInWindow "My Window" (200, 200) (10, 10) white pict

El bloque do es superfluo porque solo tiene una declaración, y puede mover la aplicación final fuera de la definición:

let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white . Pictures . map Line . map (map mkPt) . blocks in displayPict pes

Puedes fusionar los dos map s:

let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white . Pictures . map (Line . map mkPt) . blocks in displayPict pes

A veces también es más legible que las cadenas largas utilicen el operador de composición invertida de Control.Arrow :

let displayPict = blocks >>> map (Line . map mkPt) >>> Pictures >>> displayInWindow "My Window" (200, 200) (10, 10) white in displayPict pes

Pero todo eso es opcional; Sazona tu código a gusto.

En cuanto al tema de la eficiencia, no veo ninguna razón para pensar que los dos serían diferentes, una vez que el optimizador de GHC haya terminado con el código.


El estilo de punto libre puede ser bueno para mostrar claramente que una función es simplemente una serie de transformaciones en una entrada. Es muy fácil leer algo como:

foo = map show . doThis . doThat . etc

porque parece un código típico sin puntos, por lo que alguien familiarizado con él podrá ver exactamente lo que es importante, sin ruido. Compara esto con:

foo x = d where a = etc x c = doThis b b = doThat a d = map show c

Obviamente, esto es un poco artificial, pero la idea es que las definiciones adicionales deben leerse y prestarse mucha atención para comprender lo que realmente está haciendo foo . ¿Se utiliza como argumento para más de una función auxiliar? ¿Qué hay de b ? ¿Los datos fluyeron a través de estas funciones de ayuda de una manera inesperada? El estilo de punto libre en este caso es: "Las cosas solo se están transformando en una tubería, no hay ninguna rareza en la que debas pensar"

En otros casos, el estilo sin puntos realmente puede ofuscar cosas. Por lo general, es cuando se rompen los let y wheres. Por lo tanto, la terseness no es realmente el único objetivo, reducir la carga mental también es importante. (Como han comentado otros, el estilo sin puntos no debería tener una diferencia de rendimiento en el código optimizado).