list-helpers.scm 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. (library (list-helpers)
  2. (export list-right-pad
  3. flatten)
  4. (import
  5. (except (rnrs base) let-values map)
  6. (only (guile)
  7. lambda* λ)
  8. (ice-9 match))
  9. (define list-right-pad
  10. (λ (lst pad-count pad-value)
  11. (cond
  12. [(= pad-count 0) lst]
  13. [(null? lst)
  14. (cons pad-value
  15. (list-right-pad lst
  16. (- pad-count 1)
  17. pad-value))]
  18. [else
  19. (cons (car lst)
  20. (list-right-pad (cdr lst)
  21. (- pad-count 1)
  22. pad-value))])))
  23. ;; This one is a read brain twister.
  24. (define (flatten lst)
  25. (let loop ([remaining-lst lst]
  26. [acc '()])
  27. (cond
  28. [(null? remaining-lst) acc]
  29. ;; If we have a list recur with the head of the list and the
  30. ;; cdr. Since the acc argument will be consed to the end
  31. ;; ultimately (see else branch), we can call loop for the head
  32. ;; of the list and use the result of flattening the tail of the
  33. ;; list as new acc.
  34. ;; Since the evaluation order is to evaluate arguments for
  35. ;; function calls first, we put off the flattening of the head
  36. ;; of the list until later. The tail of the list will be
  37. ;; flattened first.
  38. [(pair? remaining-lst)
  39. ;; If head is an atom the call will go the the else branch,
  40. ;; where it will be the `remaining-lst`. It will wait there to
  41. ;; be consed onto the result for the other call to loop. This
  42. ;; basically builds up a chain of cons, each waiting for the
  43. ;; second argument to be computed.
  44. ;; If head is a list, it will be flattened, which results in
  45. ;; having the cons chain for that list, which waits for the
  46. ;; flattened tail to be consed onto that.
  47. ;; The acc argument is used to thread in the results of
  48. ;; flattening parts of the list, which will only be seen
  49. ;; later. It provides a handle onto the later flattened parts
  50. ;; of the list, to be consed onto those in the else branch. It
  51. ;; is quite clever actually.
  52. (loop (car remaining-lst)
  53. (loop (cdr remaining-lst)
  54. acc))]
  55. ;; If we have an atom, use the atom as is and cons it onto the
  56. ;; accumulated. The value for acc is computed in the (pair?
  57. ;; remaining-lst) branch, by another call to loop.
  58. [else
  59. (cons remaining-lst acc)]))))