Search code examples
functional-programmingf#unzip

F# (F sharp) unzip function explained


I'm taking a university course in functional programming, using F#, and I keep getting confused about the logical flow of the following program. Would anyone care to explain?

let rec unzip = function
    |    []          ->  ([],[])
    |    (x,y)::rest ->
               let (xs,ys) = unzip rest
               (x::xs,y:ys);;

So this program is supposed to take a list of pairs, and output a pair of lists.

[(1,'a');(2,'b')] -> ([1;2],['a','b'])

It seems to me, like the base case where the argument (list) is empty, the format of the output is given, but I don't understand how the third and fourth line is evaluated.

let (xs,ys) = unzip rest
(x::xs,y:ys);;

Solution

  • Firstly, this is a recursive function - the rec keyword is a giveawy :).

    These can be quite hard to get you head around, but are quite common in functional programming.

    I'll assume you are OK with most of the pattern matching going on, and that you are aware of the function keyword shorthand.

    let rec unzip = function
        |    []          ->  ([],[])
        |    (x,y)::rest ->
                   let (xs,ys) = unzip rest
                   (x::xs,y:ys);;
    

    You seem quite happy with:

    |    []          ->  ([],[])
    

    Given an empty list, return a tuple with 2 empty lists. This isn't just a guard clause, it will be used later to stop the recursive program running forever.

    The next bit...

    |    (x,y)::rest ->
    

    Takes the first element (head) of the list and splits it off from the tail. It also deconstructs the head element which is a tuple into 2 values x and y.

    The could be written out long hand as:

    |    head::rest ->
              let x,y = head
    

    Now is the fun part where it calls itself:

    let (xs,ys) = unzip rest
    (x::xs,y:ys);;
    

    It might help to walk though an example an look at what goes on at each step:

    unzip [(1,'a');(2,'b');(3,'c')]
     x = 1
     y = 'a'
     rest = [(2,'b'); (3,'c')]
     unzip rest
      x = 2
      y = 'b'
      rest = [(3,'c')]
      unzip rest
       x = 3
       y = 'c'
       rest = []
       unzip rest
         return [],[]
       xs = []
       ys = []
       return [x:xs],[y:ys]     # 3:[] = [3], 'c':[] = ['c']
      xs = [3]
      ys = ['b']
      return [x:xs],[y:ys]      # 2:[3] = [2,3], 'b':['c'] = ['b', 'c']
     xs = [2,3]
     ys = ['b','c']
     return [x:xs],[y:ys]       # 1:[2;3] = [1,2,3], ['a']:['b';'c'] = ['a', 'b', 'c']
    done