[Haskell-cafe] beginner's problem about lists

Henning Thielemann lemming at henning-thielemann.de
Tue Oct 10 09:38:51 EDT 2006


On Tue, 10 Oct 2006, Henning Thielemann wrote:

> 
> On Tue, 10 Oct 2006 falseep at gmail.com wrote:
> 
> > Hi all,
> > 
> > I'm trying to implement a function that returns the shorter one of two given
> > lists,
> > something like
> > shorter :: [a] -> [a] -> [a]
> > such that shorter [1..10] [1..5] returns [1..5],
> > and it's okay for shorter [1..5] [2..6] to return either.
> > 
> > Simple, right?
> > 
> > However, it becomes difficult when dealing with infinite lists, for example,
> > shorter [1..5] (shorter [2..] [3..])
> > Could this evaluate to [1..5]? I haven't found a proper implementation.
> > 
> > Again it's ok for shorter [2..] [3..] to return whatever that can solve
> > the above problem correctly.
> > An infinite list could work, I guess, but I don't know how.
> 
> With PeanoNumbers,
>    http://darcs.haskell.org/htam/src/Number/PeanoNumber.hs
>  I would first attach a lazy length information to each list before any
> call to 'shorter', then I would remove this information after the last
> call to 'shorter'.
> 
> Untested code follows:
> 
> attachLength :: [a] -> (PeanoNumber.T, [a])
> attachLength xs = (genericLength xs, xs)
> 
> detachLength :: (PeanoNumber.T, [a]) -> [a]
> detachLength = snd 
> 
> shorter :: (PeanoNumber.T, [a]) -> (PeanoNumber.T, [a]) -> (PeanoNumber.T, [a])
> shorter (xl,xs) (yl,ys) = (min xl yl, if xl < yl then xs else ys)


Ah, here is a simpler solution:

compareLength :: [a] -> [b] -> Ordering
compareLength (_:xs) (_:ys) = compareLength xs ys
compareLength []     []     = EQ
compareLength (_:_)  []     = GT
compareLength []     (_:_)  = LT

shorter :: [a] -> [a] -> [a]
shorter xs ys =
   let lt = compareLength xs ys == LT
   in  zipWith (\x y -> if lt then x else y) xs ys


zipWith returns the length of the shorter list lazily and the elements are
chosen after the shortest list is determined.


More information about the Haskell-Cafe mailing list