2

For a class, I was trying to come up with simple examples of strict and non-strict functions, arguing that non-strict functions make sense. One of my examples was that it might be useful to define 0*x = x*0 = 0 for all x in the domain. When I got back home I naturally wanted to see what the Haskell creators think about that. Here comes my confusion.

At one machine, ghci says that multiplication is strict on both arguments:

GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> 0 * undefined 
*** Exception: Prelude.undefined
Prelude> undefined * 0
*** Exception: Prelude.undefined

At another machine, ghci says that multiplication is non-strict on the first argument:

GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude> undefined * 0
0
Prelude> 0 * undefined
*** Exception: Prelude.undefined

What causes the difference in behaviour ?

stefk0
  • 56
  • 5
  • I don't know the answer to your question, but for examples of why laziness is useful you might like [Non-Trivial Lazy Evaluation](http://stackoverflow.com/questions/7868507/non-trivial-lazy-evaluation). – Daniel Wagner Nov 15 '16 at 20:19
  • 5
    That is the result of a [bug in GHC 7.10.3](http://stackoverflow.com/questions/36049689/why-does-multiplication-only-short-circuit-on-one-side) which didn't exist before 7.10 and was eliminated in 8.1. – David Young Nov 15 '16 at 20:22
  • OK. Thanks. Do you know what is the reasoning behind the decision to make multiplication strict? From my point of view, this is not obvious, because I make a parallel with the fact that True || undefined = True. – stefk0 Nov 15 '16 at 20:29
  • 2
    Also, you won't be able to implement a completely lazy `0 * x = x * 0 = 0` in Haskell. One of the sides will need to be evaluated to make sure the first pattern doesn't match (which one depends on which pattern match you put first in your definition). – David Young Nov 15 '16 at 20:30
  • 2
    I think the reason multiplication is strict is that it would cause a significant performance decrease if it was lazy. If it was lazy in (say) the first argument, something like `((... * x) * y) * z` (with a lot of factors) would need to build up a huge thunk before any actual work (multiplication) can be done. – David Young Nov 15 '16 at 20:33
  • 2
    It is possible to have a multiplication that is non strict in both arguments using lub (experimental module), see [ptimes](http://hackage.haskell.org/package/lub-0.1.7/docs/Data-Lub.html) – luqui Nov 15 '16 at 21:00

1 Answers1

1

The answer is in the comments thanks to @DavidYoung - this is a GHC bug nothing more.

If you want multiplication to be lazy in some particular manner you can certainly write your own type and instance for Num. For example:

module Main where

main :: IO ()
main =
  do print (one * two)
     print (undefined * zero)
     putStrLn "The next one has an exception because it must evaluate the undefined arugment."
     print (undefined * two)

one, two, zero :: LazyInt
one = 1
two = 2
zero = 0

-- Not fully lazy such as in addition or Ord, which is possible,
-- but just in the first argument for multiplication.
newtype LazyInt = LI { unLI :: Int }
                deriving (Eq, Ord)

instance Show LazyInt where
  show (LI x) = show x

instance Num LazyInt where
  (LI a) + (LI b) = LI (a + b)
  negate (LI a) = LI (negate a)
  abs (LI a) = LI (abs a)
  signum (LI a) = LI (signum a)
  fromInteger i = LI (fromInteger i)

  -- The case of interest:
  a * (LI b) =
    if b == 0
       then LI 0
       else LI (unLI a * b)
Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166