Прокомментирую только приведённый код.
Во-первых, в многоаргументных функциях $! нужно делать не только на внешнем уровне, но и на всех остальных, т.е.
(f $! x) $! y
, иначе строгость относится только к первому аргументу и созданию
чанка.
Во-вторых, компилятор хитёр, но один из вариантов его обдурить заключается в оборачивании вычисляемого выражения в хитрую монаду. Хитрее IO придумать сложно.
import Data.Time
testTime n func arg1 arg2 = let
list = (replicate $! n) $! (arg1, arg2)
func' ~(x, y) = return $ (func $! x) $! y
in do
start <- getCurrentTime
sequence $ (map $! func') $! list
stop <- getCurrentTime
print (diffUTCTime stop start)