[Haskell-beginners] Haskell triangular loop (correct use of (++))

AntC anthony_clayden at clear.net.nz
Sat Apr 23 00:20:58 UTC 2016


> rohan sumant <r.s.sumant <at> gmail.com> writes:
>
>  The approach I am following is this :-
> mkpairs [] = []
> 
> mkpairs (x:xs) = (map (fn x) xs) ++ (mkpairs xs)
> fn x y = (x,y)
> 
> It is generating the desired output ...

Good! You've got the right approach for triangular loops.
That is a form

mkpairs (x:xs) = {- stuff -} $ mkpairs xs

A couple of things look non-idiomatic. So before I get on to your main question:

As well as an empty list being a special case,
neither can you make any pairs from a singleton ;-). I suggest:

mkpairs [x] = []

The auxiliary `fn` is messy. I would put explicit lambda:

mkpairs (x:xs) = map (\x' -> (x, x') ) xs ++ mkpairs xs

Or even switch on tuple sections 
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/
syntax-extns.html#tuple-sections

mkpairs (x:xs) = map (x, ) xs ++ mkpairs xs

> but I am a bit unsure about the time complexity of the function mkpairs. ...
> I am particularly worried about the (++) operator. ...

You are spot-on! (++) has terrible time complexity.
Use the showS trick for constant-time concatenation.
Look in the Prelude for class Show a/method showsPrec,
explained in the Haskell 2010 report section 6.3.3.

To get that to work, you need a 'worker' function
to hand across the successor for each list.
It's conventional to call that `go`,
and because everyone uses `go`,
wrap it inside mkpairs using a `where`.

Complete code:

mkPairs [] = []
mkPairs [x] = []
mkPairs (x:xs) = go xs $ mkPairs xs
  where go [] s = s
             go (x':xs') s = (x, x') : go xs' s

Now is that any faster in practice?
Probably not until you get to a list with thousands of elements.

HTH


More information about the Beginners mailing list