[Haskell-cafe] unneeded strictness

Serge D. Mechveliani mechvel at botik.ru
Wed Oct 20 05:47:46 EDT 2004

Dear Haskellers,

I am still trying to find out how to organize naturally a
`lazy' printing of an accumulated data field.

People advised me  no-buffering  and also the  tilde  usage.
But there is some more obstackle.

The `trace' is accumulated in  fl1  by repeating  consD,  

  data D = D {fl1 :: String, fl2 :: String}

  consD :: Char -> D -> D
  consD    a       d =  d {fl1 = a:(fl1 d)}

(tilde is not needed here?)

The whole process computes  res :: D  in a certain complex 
recursive manner. One of the ways to use  res  is to print out 
the `trace' field:
                   let  res = (complexProcess ...)  :: D
                   show $ fl1 res

I need  fl1 res  to be formed `lazily'.
For example, 
             take 2 $ fl1 res   may be ready (and shown) immediately, 
and          last   $ fl1 res   may be ready long after.

If it was  [Char]  istead of  D,  then this would be easy.
                   head $ (a:) xs  =  a

For example,       head $ ('a':) $ (error "")  =  'a'

But is this true for  consD and headD, where

  headD :: D -> Char
  headD =  head . fl1
That is    headD $ consD a res  =?=  a

If  res  is not a bottom,  then, yes.  
And if  res  occurs, say,  (error ""),  then  consD  cannot intrude
into  fl1 res,  and the whole expression has a value _|_.
So, generally,  headD $ consD a res  is not equivalent to  a;
hence the head members of  fl1 res  have to wait at least until it 
becomes clear that  res  is not a bottom.

So far, I see the two way-outs.

1. To insert the usage of the `trace' tool 
   -- which does not look nice.

2. To have a result   res :: [D]  instead of D.
And as soon as a new  step  appears, form  res ++[d {fl1 = [step]}]
                                           d = last res,
   fl2 also can be modified.
   Now,                        map fl1 res 

   is the needed trace, which, I believe, would be formed `lazily'.  

I wonder
a) whether there is a nicer solution,

b) what happens if the Language treats the constructors as the 
   For example,      head $ (a:) xs  =  a  
                     head $ fl1 $ D {fl1 = (a:) fl1}  =  a

   Here  (D, fl1)  is a constructor, and its insertion between
   the functions  head  and  (a:)  preserves the above relation 
   between them
   (is this called `bottom chasing' ?).
   Probably, this will eliminate unneeded strictness -- ?

Thank you in advance for the explanations.
Copy, please, the answer to                mechvel at botik.ru

Serge Mechveliani
mechvel at botik.ru

More information about the Haskell-Cafe mailing list