I've been practicing my folds and tail-call recursive programming, and I wanted to work on unzip for the general case as opposed to just pairs. This was very easy to do with standard tail call recursion. However, I was also told that any time you can use tail call recursion on a list, you could also use a fold. I was eventually able to figure out an algorithm that only uses folds, but it wasn't nearly as simple as, or even exactly a translation of, the tail recursive version. Are there any improvements or changes I could make to either of these algorithms?
Tail-call recursive
; Unzip a list of equally lengthed lists
; Takes car of every list and conses it to acc, then reverses acc at the end
; (unzip '((1 4 7 10) (2 5 8 11) (3 6 9 12))) => '((1 2 3) (4 5 6) (7 8 9) (10 11 12)
(define (unzip lst [acc '()])
(if (or (empty? lst) (empty? (car lst)))
(reverse acc)
(unzip (map cdr lst) (cons (map car lst) acc))))
Folds only:
; Takes the last element and turns it into a list of singletons as a seed
; For each remaining element, it conses each element onto its respective list
(define (unzip lst)
(define (list->singletons lst)
(foldl (λ (x acc) (cons `(,x) acc)) '() (reverse lst)))
(define (cons* heads tails)
(foldr (λ (hd tl acc) (cons (cons hd tl) acc)) '() heads tails))
(if (empty? lst)
lst
(foldl (λ (x acc) (cons* x acc))
(list->singletons (car (reverse lst))) (cdr (reverse lst)))))