Dear Haskellers, I try to organize a `lazy' output in my program, so that the data are accumulated, step by step in a pair (String, String) (a contrived simplified example). And the first component is a `story' to be printed out in a `lazy' manner, the first steps need to print without waiting for the whole data field to be ready. If the program returns String, then I can arrange this. But with (String, String), I do not know how to do. And in the real progam, it is a more complex labeled record, carried along through the program. Probably, the obstackle is in the very Haskell language. Consider a simple example: --------------------------------------------------------------- bottomStr :: String bottomStr = let xs = xs in xs bottomSPair :: (String, String) bottomSPair = let p = p in p bound = 10^8 :: Int -- some large number f1, f2, g1, g2 :: Char f1 = head ('a' : (if last [1 .. bound] > 0 then "b" else "c")) f2 = head ('a' : bottomStr) g1 = head $ fst $ addToSPair 'a' (if last [1 .. bound] > 0 then ("b", "") else ("c", "")) g2 = head $ fst $ addToSPair 'a' bottomSPair addToSPair :: Char -> (String, String) -> (String, String) addToSPair c (xs, ys ) = (c:xs, ys ) main = putStr [ f1, '\n' ] -- f2 -- g1, g2 --------------------------------------------------------------- g1 is similar to f1, g2 similar to f2. f1 and f2 are evaluated immediately to 'a'; g1 evaluates to 'a' after a long computation; g2 evaluates to Fail: <<loop>> As g2 is similar to f2, should it have a value 'a' ? In head $ fst $ addToSPair 'a' bottomSPair bottomSPair is of type (String, String). addToSPair is declared as returning (String, String). Hence, the complier knows ab initio that after addToSPair the result is of kind ('a': _, _) :: (String, String) Hence, applying further head $ fst yields 'a'. This is in the air of a `lazy' computation. In a more clear presentation, the computation should (?) be head $ fst $ addToSPair 'a' bottomSPair = head $ fst $ addToSPair 'a' (bottomStr, bottomStr) = head $ fst (`a':bottomStr, bottomStr) = head (`a':bottomStr) = 'a' So, similarly as head ('a' : bottomStr) = 'a', (1) it should be head $ fst $ addToSPair 'a' bottomSPair = 'a' (2) Probably, Haskell-98 does not put so. Right? Question 1 ---------- What may be the consequences for the language (let us call it HCLazy) if it treats the data constructors like in (2), like more `lazy' ones? For example, fst (bottom :: (a,b)) = (bottom :: a) Question 2 ---------- How to arrange the above `lazy' output? The whole result story is ready in several hours, or days, and each step should be displayed immediately as it is ready. So far, I see no other way as to compile the program together with the Trace library, inserting there the calls \ step ... -> trace (show step) $ ... (?) Thank you in advance for the explanations. Copy, please, the answer to mechvel@botik.ru ----------------- Serge Mechveliani mechvel@botik.ru
Question 2 ---------- How to arrange the above `lazy' output?
Your function addToSPair addToSPair :: Char -> (String, String) -> (String, String) addToSPair c (xs, ys ) = (c:xs, ys ) does a strict pattern match on the pair constructor. It needs to know that its second argument is a pair before it produces anything of its result. If you use a lazy pattern match addToSPair :: Char -> (String, String) -> (String, String) addToSPair c ~(xs, ys ) = (c:xs, ys ) instead, it doesn't need to evaluate this argument immediately. Regards, Sander
On 13 Oct 2004, at 06:59, Serge D. Mechveliani wrote:
bottomStr :: String bottomStr = let xs = xs in xs
bottomSPair :: (String, String) bottomSPair = let p = p in p
Note here that bottomSPair is bottom...
addToSPair :: Char -> (String, String) -> (String, String) addToSPair c (xs, ys ) = (c:xs, ys )
In a more clear presentation, the computation should (?) be
head $ fst $ addToSPair 'a' bottomSPair = head $ fst $ addToSPair 'a' (bottomStr, bottomStr)
...so this step is wrong: bottomSPair is not the same as the pair (bottomStr, bottomStr). Haskell pairs are lifted: (bottom,bottom) is different from bottom.
bottomSPair is of type (String, String). addToSPair is declared as returning (String, String). Hence, the complier knows ab initio that after addToSPair the result is of kind ('a': _, _) :: (String, String)
No. The result is necessarily of type (String,String), but need not be a proper pair. (And indeed, addToSPair c bottom yields bottom, not a proper pair.)
So, similarly as head ('a' : bottomStr) = 'a', (1) it should be head $ fst $ addToSPair 'a' bottomSPair = 'a' (2)
Question 1 ---------- What may be the consequences for the language (let us call it HCLazy) if it treats the data constructors like in (2), like more `lazy' ones?
That is, what if Haskell had unlifted pairs? Interesting question. Nils Anders Danielsson (http://www.cs.chalmers.se/~nad/) has been looking at it, with his work on Chasing Bottoms (http://www.cs.chalmers.se/~nad/software/ChasingBottoms/docs/).
For example, fst (bottom :: (a,b)) = (bottom :: a)
I don't think this example is what you mean. This applies in Haskell already. I think what you mean is that (fst p, snd p) equals p for every p, including p=bottom.
How to arrange the above `lazy' output? The whole result story is ready in several hours, or days, and each step should be displayed immediately as it is ready.
Another poster mentioned the possibility of using an irrefutable pattern (by adding a tilde). Equivalently, you can define
addToSPair :: Char -> (String, String) -> (String, String) addToSPair c p = (c : fst p, snd p)
Then addToSPair c bottom is (c:bottom,bottom) as you're hoping, not bottom. Jeremy
participants (3)
-
Jeremy Gibbons -
Sander Evers -
Serge D. Mechveliani