2016-11-15 3 views
2

Für eine Klasse habe ich versucht, einfache Beispiele für strikte und nicht-strikte Funktionen zu finden, mit dem Argument, dass nicht-strikte Funktionen sinnvoll sind. Eines meiner Beispiele war, dass es nützlich sein könnte, 0 * x = x * 0 = 0 für alle x in der Domäne zu definieren. Als ich nach Hause kam, wollte ich natürlich sehen, was die Haskell-Schöpfer darüber denken. Hier kommt meine Verwirrung.strenge oder nicht-strikte Multiplikation in Haskell?

An einer Maschine, GHCI sagt, dass die Multiplikation auf beiden Argumente streng:

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 

Bei einer anderen Maschine, sagt GHCI, dass die Multiplikation auf dem ersten Argument nicht streng ist:

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

Was verursacht den Unterschied im Verhalten?

+0

ich nicht die Antwort auf Ihre Frage nicht kennen, aber für Beispiele, warum Faulheit ist nützlich, die Dir vielleicht gefallen [Non-Trivial Lazy Evaluation] (http://stackoverflow.com/questions/7868507/nicht-trivial-lazy-evaluation). –

+5

Das ist das Ergebnis eines [Bug in GHC 7.10.3] (http://stackoverflow.com/questions/36049689/why-does-multiplication-only-short-circuit-on-one-side), die nicht existiert vor 7.10 und wurde in 8.1 eliminiert. –

+0

OK. Vielen Dank. Weißt du, was der Grund für die Entscheidung ist, die Multiplikation streng zu machen? Aus meiner Sicht ist das nicht offensichtlich, da ich eine Parallele zu der Tatsache mache, dass True || undefiniert = Wahr. – stefk0

Antwort

1

Die Antwort ist in den Kommentaren dank @DavidYoung - das ist ein GHC-Bug nichts mehr.

Wenn Sie möchten, dass die Multiplikation auf eine bestimmte Weise faul ist, können Sie sicherlich Ihren eigenen Typ und Ihre eigene Instanz für Num schreiben. Zum Beispiel:

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)