Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewPatterns and multiple calls in Haskell

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
like image 804
julx Avatar asked Jan 20 '12 20:01

julx


1 Answers

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.)

like image 96
ehird Avatar answered Sep 24 '22 08:09

ehird