es el punto de código libre más eficiente, o simplemente tersa?


Escribí el siguiente código, que toma un montón de puntos y los dibuja en la pantalla utilizando 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 de función, el resultado de cada una alimentando el último argumento del siguiente. Así que refactoricé eliminando las variables intermedias, invirtiendo el orden y encadenando las funciones con la composición de la función (".") así:

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

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

Author: Will Ness, 2011-06-27

2 answers

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 se pueden eliminar directamente:{[13]]}

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ás evitando los paréntesis con el término map (map mkPt), así que deshazte del $:

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 instrucció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

Puede fusionar el dos maps:

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 para cadenas largas usar 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; sazone su código al gusto.

Sobre el 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.

 31
Author: C. A. McCann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-27 14:52:57

El estilo libre de puntos puede ser bueno para mostrar muy 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 se parece al típico código sin puntos, por lo que alguien familiarizado con él podrá ver exactamente lo que es importante, sin ruido. Compare 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 entiende lo que foo está haciendo realmente. ¿Se usa a como argumento para más de una función auxiliar? ¿Qué pasa con b? ¿Los datos fluyeron a través de estas funciones auxiliares de una manera inesperada? Point free style en este caso está diciendo"Las cosas se están transformando en una tubería, no hay rarezas en las que deba pensar"

En otros casos, el estilo sin puntos realmente puede ofuscar las cosas. En general, es cuando se rompería los lets y wheres. Así que, la tersura no es realmente el único objetivo, reducir la carga mental también es importante. (Como otros han comentado, el estilo point free no debería tener una diferencia de rendimiento en el código optimizado).

 4
Author: deontologician,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-29 17:49:25