vectores una producto por multiplicar matriz matrices listas inversa ejercicios ejemplos con comprension haskell short-circuiting

haskell - una - ¿Por qué la multiplicación solo cortocircuita en un lado?



producto de matrices haskell (3)

En realidad, parece que fix (* 0) == 0 solo funciona para Integer , si ejecuta fix (* 0) :: Double o fix (* 0) :: Int , todavía obtiene ***Exception <<loop>>

Eso es porque en el instance Num Integer , (*) se define como (*) = timesInteger

timesInteger se define en Data.Integer

-- | Multiply two ''Integer''s timesInteger :: Integer -> Integer -> Integer timesInteger _ (S# 0#) = S# 0# timesInteger (S# 0#) _ = S# 0# timesInteger x (S# 1#) = x timesInteger (S# 1#) y = y timesInteger x (S# -1#) = negateInteger x timesInteger (S# -1#) y = negateInteger y timesInteger (S# x#) (S# y#) = case mulIntMayOflo# x# y# of 0# -> S# (x# *# y#) _ -> timesInt2Integer x# y# timesInteger x@(S# _) y = timesInteger y x -- no S# as first arg from here on timesInteger (Jp# x) (Jp# y) = Jp# (timesBigNat x y) timesInteger (Jp# x) (Jn# y) = Jn# (timesBigNat x y) timesInteger (Jp# x) (S# y#) | isTrue# (y# >=# 0#) = Jp# (timesBigNatWord x (int2Word# y#)) | True = Jn# (timesBigNatWord x (int2Word# (negateInt# y#))) timesInteger (Jn# x) (Jn# y) = Jp# (timesBigNat x y) timesInteger (Jn# x) (Jp# y) = Jn# (timesBigNat x y) timesInteger (Jn# x) (S# y#) | isTrue# (y# >=# 0#) = Jn# (timesBigNatWord x (int2Word# y#)) | True = Jp# (timesBigNatWord x (int2Word# (negateInt# y#)))

Mira el código de arriba, si ejecutas (* 0) x , entonces el número de timesInteger _ (S# 0#) coincidiría para que x no se evalúe, mientras que si ejecutas (0 *) x , entonces al verificar si el tiempo timesInteger _ (S# 0#) coincide, x sería evaluado y causar bucle infinito

Podemos usar el siguiente código para probarlo:

module Test where import Data.Function(fix) -- fix (0 ~*) == 0 -- fix (~* 0) == ***Exception<<loop>> (~*) :: (Num a, Eq a) => a -> a -> a 0 ~* _ = 0 _ ~* 0 = 0 x ~* y = x ~* y -- fix (0 *~) == ***Exception<<loop>> -- fix (*~ 0) == 0 (*~) :: (Num a, Eq a) => a -> a -> a _ *~ 0 = 0 0 *~ _ = 0 x *~ y = x *~ y

Hay algo aún más interesante, en GHCI:

*Test> let x = fix (* 0) *Test> x 0 *Test> x :: Double *** Exception: <<loop>> *Test>

Estuve jugando con la fix y después de jugar con eso me encontré con un comportamiento extraño, a saber, que 0 * undefined es *** Exception: Prelude.undefined y undefined * 0 is 0 . Lo que también significa que fix (0 *) es *** Exception: <<loop>> y fix (* 0) es 0 .

Después de jugar con él parece que la razón es porque no es trivial hacerlo cortocircuito en ambas direcciones, ya que eso no tiene mucho sentido, sin algún tipo de cálculo paralelo extraño y comenzar con el primer no- fondo devuelto.

¿Se ve este tipo de cosas en otros lugares (funciones reflexivas que no son reflexivas para los valores mínimos) y es algo en lo que puedo confiar con seguridad? También hay una forma práctica de hacer que tanto (0 *) como (* 0) evalúen a cero independientemente del valor que se haya ingresado.


Tome lo siguiente, por ejemplo

(if expensiveTest1 then 0 else 2) * (if expensiveTest2 then 0 else 2)

Tienes que elegir un lado para evaluar. Si expensiveTest2 es un ciclo infinito, nunca podrás saber si el lado derecho es 0 o no, por lo que no puedes decir si debes o no cortocircuitar el lado derecho, por lo que nunca podrás mirar el lado izquierdo. No puede verificar si ambos lados son 0 a la vez.

En cuanto a si puede confiar en un cortocircuito para actuar de cierta manera, solo tenga en cuenta que el error undefined y el acto exactamente igual a un bucle infinito, siempre y cuando no utilice IO. Por lo tanto, puede probar el cortocircuito y la pereza usando undefined y error . En general, el comportamiento de cortocircuito varía de una función a otra. (También hay diferentes niveles de pereza, undefined y Just undefined puede dar resultados diferentes).

Mira this para más detalles.


Tu razonamiento es correcto Existe un paquete de unamb que proporciona herramientas para el tipo de cómputo paralelo al que se refiere. De hecho, ofrece Data.Unamb.pmult , que intenta, en paralelo, verificar si cada operando es 1 o 0, y si es así inmediatamente produce un resultado. ¡Es probable que este enfoque paralelo sea mucho más lento en la mayoría de los casos para la aritmética simple!

El cortocircuito de (*) ocurre solo en GHC versión 7.10. Se produjo como resultado de los cambios en la implementación del tipo Integer en esa versión de GHC. Esa holgazanería adicional generalmente se consideraba un error de rendimiento (ya que interfiere con el análisis de rigor e incluso puede generar fugas de espacio en teoría), por lo que se eliminará en GHC 8.0.