Thanks to  Matt Harden     <[EMAIL PROTECTED]>
and        Carsten Schultz <[EMAIL PROTECTED]>

for their helpful comments on 
  zipRem :: [a] -> [b] -> [(a,b),[a],[b]) 
                                   -- zip preserving remainder lists
  zipRem []     ys     = ([], [], ys)   
  zipRem xs     []     = ([], xs, [])
  zipRem (x:xs) (y:ys) = case  zipRem xs ys  
                         of 
                           (ps,xs',ys') -> ((x,y):ps, xs', ys')

I complained recently on that it compiles into a space hungry thing.
Mutt Harden says that the matter is in that this recursion is not a
tail-recursion. And gives a nice tail-recursive version of the 
algorithm, using accumulator function of composed (x:).

If so, then, how many Standard Library functions can improve this
way?
Generally, it is too easy to write a space eater in Haskell. 
The compilers do not care much.
The below function is not of Standard, but presents certain simplest
example (sorry if it is wrongly cited):

  allMaybes :: [Maybe a] -> Maybe [a]
  allMaybes []           = Just []
  allMaybes (Nothing:_ ) = Nothing
  allMaybes (Just x :ms) = case  allMaybes ms  of  
                                              Nothing -> Nothing
                                              Just xs -> Just (x:xs)
Now,  isJust $ allMaybes $ map Just [1..n]

is likely to need the _stack_ proportional to  n.
Instead,
  am ms = a [] ms  where  a xs []           = Just $ reverse xs
                          a _  (Nothing:_ ) = Nothing
                          a xs (Just x :ms) = a (x:xs) ms
will require a constant stack.

Again, why the compilers themself do not understand simplest 
possibilities to convert to the tail recursion?

Maybe, Carsten Schultz gives some answer:

> your zipRem [..]
> is stricter than you probably want it to be:  Due to the use of 
> case you have, e.g.,
>                      zipRem (0:_|_) [0] = _|_.
> Try instead
> [..]
> zipRem2 (x:xs) (y:ys) = ((x,y):ps, xs', ys') where
>       (ps, xs', ys') = zipRem2 xs ys
> [..]


So, maybe, the compiler converts  zipRem2  into tail recursion,
and cannot do this to  zipRem  due to the different meaning of
`case' and `where' (`let'). 

Do I understand right?

  head $ tuple31 $ zipRem2 (1:undefined) --> 1
  head $ tuple31 $ zipRem  (1:undefined) --> undefined

Why Haskell is so? Why  case  zipRem undefined []
                        of 
                          (ps,xs',ys') -> ((x,y):ps, xs', ys')

does not allow the result of           zipRem undefined []  
to be of                               (ps,xs',ys')
(which type is declared in  zipRem) ?
And `let', `where' do allow this.

Now, the simpler example:
  f []     = []
  f (x:xs) = case  f xs  of  ps -> (x,x):ps
 
  head $ f (1:undefined) --> (1,1)

Here `case' behaves differently. I am about totally confused.
The past century was not enough to study the basic Haskell.
Maybe, the constructor (,,) in the zipRem pattern forces some kind
of strictness, I do not know.

------------------
Sergey Mechveliani
[EMAIL PROTECTED]

Reply via email to