haskell - para - Definir la aplicación estricta($!) Yo mismo no resulta en el mismo rendimiento
haskell platform (1)
Estoy leyendo esta entrada de blog de Michael Snoyman recientemente. En un ejercicio sugerido allí, traté de definir $!
operador por mi cuenta:
import Prelude hiding ( ($!) )
($!) :: (a -> b) -> a -> b
($!) f x = x `seq` f x
mysum :: [Int] -> Int
mysum list0 =
go list0 0
where
go [] total = total
go (x:xs) total = go xs $! total + x
main = print $ mysum [1..1000000]
Pensé que esto funciona bien, aunque el uso de la memoria era terrible. Mi primera pregunta es la siguiente. ¿Por qué no funcionó bien?
Entonces, comprobé su definición en Preludio. Se lee:
($!) :: (a -> b) -> a -> b
f $! x = let !vx = x in f vx -- see #2273
Entonces, lo copié en mi código:
{-# LANGUAGE BangPatterns #-}
import Prelude hiding ( ($!) )
($!) :: (a -> b) -> a -> b
($!) f x =
let !vx = x
in f vx
mysum :: [Int] -> Int
mysum list0 =
go list0 0
where
go [] total = total
go (x:xs) total = go xs $! total + x
main = print $ mysum [1..1000000]
y el resultado fue:
Linking mysum4 ...
500000500000
209,344,064 bytes allocated in the heap
130,602,696 bytes copied during GC
54,339,936 bytes maximum residency (8 sample(s))
66,624 bytes maximum slop
80 MB total memory in use (0 MB lost due to fragmentation)
¡Puedes ver cuán terrible es esto comparado con el resultado de usar $!
de Prelude $!
operador:
Linking mysum4 ...
500000500000
152,051,776 bytes allocated in the heap
41,752 bytes copied during GC
44,384 bytes maximum residency (2 sample(s))
21,152 bytes maximum slop
1 MB total memory in use (0 MB lost due to fragmentation)
Mi segunda pregunta es ¿de dónde viene esta diferencia?
Además, creo que puede reescribirse así:
($!) :: (a -> b) -> a -> b
f $! !x = f x
¿Hay alguna razón para no hacer esto? Esta es mi tercera pregunta.
Jajaja Es un tema de precedencia. Se te olvidó pegar la línea:
infixr 0 $!
y así, cuando usas tu propia versión, se analiza como
go (x:xs) total = (go xs $! total) + x
que obviamente tiene un rendimiento terrible. Es casi una coincidencia que incluso te da la respuesta correcta.