Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining strict application ($!) myself does not result in the same performance

Tags:

haskell

ghc

I'm reading this blog post by Michael Snoyman recently. In an exercise suggested there, I tried to define $! operator by myself:

import Prelude hiding ( ($!) )

($!) :: (a -> b) -> a -> b
($!) f x = x `seq` f x

mysum :: [Int] -> Int
mysum list0 =
  go list0 0
  where
    go [] total = total
    go (x:xs) total = go xs $! total + x

main = print $ mysum [1..1000000]

I thought this works well, though the usage of memory was terrible. My first question is this. Why didn't this work well?

Then, I checked its definition in Prelude. It reads:

($!)                    :: (a -> b) -> a -> b
f $! x                  = let !vx = x in f vx  -- see #2273

So, I copied it into my code:

{-# LANGUAGE BangPatterns #-}

import Prelude hiding ( ($!) )

($!) :: (a -> b) -> a -> b
($!) f x =
  let !vx = x
   in f vx

mysum :: [Int] -> Int
mysum list0 =
  go list0 0
  where
    go [] total = total
    go (x:xs) total = go xs $! total + x

main = print $ mysum [1..1000000]

and the result was:

Linking mysum4 ...
500000500000
     209,344,064 bytes allocated in the heap
     130,602,696 bytes copied during GC
      54,339,936 bytes maximum residency (8 sample(s))
          66,624 bytes maximum slop
              80 MB total memory in use (0 MB lost due to fragmentation)

You can see how terrible this is compared to the result of using Prelude's $! operator:

Linking mysum4 ...
500000500000
     152,051,776 bytes allocated in the heap
          41,752 bytes copied during GC
          44,384 bytes maximum residency (2 sample(s))
          21,152 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

My second question is where did this difference come from?

Furthermore, I think it can be re-written like this:

($!) :: (a -> b) -> a -> b
f $! !x = f x

Is there any reason not to do this? This is my third question.

like image 1000
Marronnier Avatar asked Apr 15 '18 06:04

Marronnier


People also ask

What is personal bias in performance appraisal?

Personal Biases: The way a supervisor feels about each of the individuals working under him - whether he likes or dislikes them - as a tremendous effect on the rating of their performances.

Why is it important to manage your own performance?

Being able to manage yourself and your own performance is an attribute that employers look for as employees who are well organised, understand their role and are always looking to increase their skills and knowledge through research, training or other means are likely to have a positive effect on their organisation.


1 Answers

Aha! It's a precedence issue. You forgot to paste the line:

infixr 0  $!

and so when you use your own version, it gets parsed as

go (x:xs) total = (go xs $! total) + x

which obviously has terrible performance. It's almost a coincidence that it even gives you the right answer.

like image 169
luqui Avatar answered Nov 14 '22 16:11

luqui