{-# LANGUAGE ExistentialQuantification #-}

import Data.Typeable
import Data.Maybe
import System.CPUTime
import System.Environment
import Unsafe.Coerce

data Any = forall a. (Typeable a) => Any a

sum1 :: [Any] -> Int
sum1 [] = 0
sum1 (Any x:xs) = (fromJust (cast x) :: Int) + sum1 xs

sum2 :: [Any] -> Int
sum2 [] = 0
sum2 (Any x:xs) = head (fromJust (cast x) :: [Int]) + sum2 xs

sum3 :: [Any] -> Int
sum3 [] = 0
sum3 (Any x:xs) = head (unsafeCoerce x :: [Int]) + sum3 xs

doTime x = do
  start <- getCPUTime
  putStr "Result: "
  print x
  stop <- getCPUTime
  putStr "Time(sec): "
  print (fromIntegral (stop - start) / 1e12)

main = do
  [len] <- getArgs
  let list = [1..read len::Int]
  putStrLn "sum1"
  let x = map Any list
  doTime $ sum1 x
  doTime $ sum1 x
  doTime $ sum1 x
  putStrLn ""
  putStrLn "sum2"
  let x = map (Any . (:[])) list
  doTime $ sum2 x
  doTime $ sum2 x
  doTime $ sum2 x
  putStrLn ""
  putStrLn "sum3"
  let x = map (Any . (:[])) list
  doTime $ sum3 x
  doTime $ sum3 x
  doTime $ sum3 x
