Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use append-map in Racket (Scheme)

I don't fully understand what the append-map command does in racket, nor do I understand how to use it and I'm having a pretty hard time finding some decently understandable documentation online for it. Could someone possibly demonstrate what exactly the command does and how it works?

like image 833
kjh Avatar asked Jan 31 '13 01:01

kjh


2 Answers

The append-map procedure is useful for creating a single list out of a list of sublists after applying a procedure to each sublist. In other words, this code:

(append-map proc lst)

... Is semantically equivalent to this:

(apply append (map proc lst))

... Or this:

(append* (map proc lst))

The applying-append-to-a-list-of-sublists idiom is sometimes known as flattening a list of sublists. Let's look at some examples, this one is right here in the documentation:

(append-map vector->list '(#(1) #(2 3) #(4)))
'(1 2 3 4)

For a more interesting example, take a look at this code from Rosetta Code for finding all permutations of a list:

(define (insert l n e)
  (if (= 0 n)
      (cons e l)
      (cons (car l) 
            (insert (cdr l) (- n 1) e))))

(define (seq start end)
  (if (= start end)
      (list end)
      (cons start (seq (+ start 1) end))))

(define (permute l)
  (if (null? l)
      '(())
      (apply append (map (lambda (p)
                           (map (lambda (n)
                                  (insert p n (car l)))
                                (seq 0 (length p))))
                         (permute (cdr l))))))

The last procedure can be expressed more concisely by using append-map:

(define (permute l)
  (if (null? l)
      '(())
      (append-map (lambda (p)
                    (map (lambda (n)
                           (insert p n (car l)))
                         (seq 0 (length p))))
                  (permute (cdr l)))))

Either way, the result is as expected:

(permute '(1 2 3))
=> '((1 2 3) (2 1 3) (2 3 1) (1 3 2) (3 1 2) (3 2 1))
like image 100
Óscar López Avatar answered Oct 30 '22 03:10

Óscar López


In Common Lisp, the function is named "mapcan" and it is sometimes used to combine filtering with mapping:

* (mapcan (lambda (n) (if (oddp n) (list (* n n)) '()))
        '(0 1 2 3 4 5 6 7))
(1 9 25 49)

In Racket that would be:

> (append-map (lambda (n) (if (odd? n) (list (* n n)) '()))
            (range 8))
'(1 9 25 49)

But it's better to do it this way:

> (filter-map (lambda (n) (and (odd? n) (* n n))) (range 8))
'(1 9 25 49)
like image 41
to_the_crux Avatar answered Oct 30 '22 01:10

to_the_crux