12

I read this:

http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns

I like the idea, want to use the extension. I however would like to make sure as to one thing: whether the view function is evaluated once for a single matching.

So let's say we have:

{-# LANGUAGE ViewPatterns #-}
...

f (view -> Nothing) = ...
f (view -> Just x) = ...

view :: a -> Maybe b

Now let's say I invoke f a. Is view invoked twice or just once for the given argument a?

EDIT:

I tried to find out whether this is the case and wrote the following:

{-# LANGUAGE ViewPatterns #-}

import System.IO.Unsafe

blah (ble -> Nothing) = 123
blah (ble -> Just x) = x

ble x = unsafePerformIO $ do
    putStrLn $ "Inside ble: " ++ show x
    return x

main :: IO ()
main = do
    putStrLn $ "Main: " ++ show (blah $ Just 234)

Output using GHC:

Inside ble: Just 234
Inside ble: Just 234
Main: 234

Output using GHC (with optimization)

Inside ble: Just 234
Main: 234

Output using GHCi:

Main: Inside ble: Just 234
Inside ble: Just 234
234
ehird
  • 40,602
  • 3
  • 180
  • 182
julx
  • 8,694
  • 6
  • 47
  • 86

1 Answers1

14

Just once:

Efficiency: When the same view function is applied in multiple branches of a function definition or a case expression (e.g., in size above), GHC makes an attempt to collect these applications into a single nested case expression, so that the view function is only applied once. Pattern compilation in GHC follows the matrix algorithm described in Chapter 4 of The Implementation of Functional Programming Languages. When the top rows of the first column of a matrix are all view patterns with the "same" expression, these patterns are transformed into a single nested case. This includes, for example, adjacent view patterns that line up in a tuple, as in

f ((view -> A, p1), p2) = e1
f ((view -> B, p3), p4) = e2

The current notion of when two view pattern expressions are "the same" is very restricted: it is not even full syntactic equality. However, it does include variables, literals, applications, and tuples; e.g., two instances of view ("hi", "there") will be collected. However, the current implementation does not compare up to alpha-equivalence, so two instances of (x, view x -> y) will not be coalesced.

The GHC manual

As for your snippet, the problem is that you're not compiling with optimisation; with both ghc -O and ghc -O2, the line is only printed once. That's always the first thing to check when you have performance-related problems when using GHC :)

(By the way, Debug.Trace lets you check these kinds of things without having to write manual unsafePerformIO hacks.)

ehird
  • 40,602
  • 3
  • 180
  • 182
  • Is it possible that GHC is inserting additional spare evaluations because of performUnsafeIO? Don't worry, I used it just to test the feature. – julx Jan 20 '12 at 20:21
  • Yes, that's me being a newbie still. Thanks a lot! – julx Jan 20 '12 at 20:35
  • 1
    For some reason I feel like using `Debug.Trace` is just fine, but `unsafePerformIO` is generally horrific, even though `Debug.Trace` just uses `unsafePerformIO` under the hood. – Dan Burton Jan 21 '12 at 01:50
  • @DanBurton Yes, you're right, I should have used `Debug.Trace` for that, it would be clearer what I wanted to do. – julx Jan 21 '12 at 16:54