
Hi, Am Samstag, den 06.12.2014, 13:08 +0100 schrieb Joachim Breitner:
on a first glance, I agree. But I wouldn’t trust my first glance until I investigated the issue.
I investigate the case for lists, which have a specialized unzip: unzip :: [(a,b)] -> ([a],[b]) {-# INLINE unzip #-} unzip = foldr (\(a,b) ~(as,bs) -> (a:as,b:bs)) ([],[]) I started with defining
let list1 = map (\c -> (c, Data.Char.ord c)) "hallo" let (uz1, uz2) = unzip list1 and then forcing list1 and uz1, but not uz2.
This gave me unzip.pdf, and you can clearly see that uz2 still references all all of the values, and a whole bunch of thunks and other annoying stuff. But: That is not due to unzip, but rather due to the lazy binding in
let (uz1, uz2) = unzip list1
If I then also force "head uz2", I get unzip_nice.pdf, where indeed uz2, despite not being forced, does not evaluate anything from uz1 any more. The same with
let !(uz1, uz2) = unzip list1
I assume this works due to GHC “Fixing some space leaks with a garbage collector“. So my conclusion is: Yes, specialized unzips do behave better behavior, but exploiting this behavior requires non-trivial knowledge about Haskell. In particular, the difference between a lazy and a strict tuple pattern. (Disclaimer: It is likely that "let (uz1, uz2) = unzip list1" would have worked in compiled code better than in GHCi due to either strictness analysis and/or “Fixing some space leaks with a garbage collector“ kicking in.) Greetings, Joachim -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org