0

Related to this question: Pair combinations in scheme, I'm trying to write a function that creates possible sequences of a list. I'm also trying to annotate it to myself with some lets, rather than putting everything in maps. Here is what I have so far:

(define (remove-from-list elem L)
  (filter (lambda (x) (not (= x elem))) L))

(define (prepend-element-to-list-of-lists elem L)
  (map (lambda (x) (append (list elem) x)) L))

(define (perm L)
  ; returns a list of lists, so base case will be '(()) rather than '()
  (if (null? L) '(())
      ; we will take out the first element, this is our "prepend-item"
      (let ((prepend-element (car L))
            (list-minus-self (remove-from-list (car L) L)))
        ; prepend-to-list-of-lists
        (let ((other-lists-minus-self (perm list-minus-self)))
          (prepend-element-to-list-of-lists prepend-element other-lists-minus-self)
          ))))
(perm3 '(1 2 3))
((1 2 3)) ; seems to be stopping before doing the recursive cases/iterations.

What I'm trying to do here is to take out the first element of a list, and prepend that to all list-of-lists that would be created by the procedure without that element. For example, for [1,2,3] the first case would be:

Take out 1 --> prepended to combinations from [2,3], and so eventually it comes to [1,2,3] and [1,3,2].

However, I was seeing if I can do this without map and just calling itself. Is there a way to do that, or is map the only way to do the above for 1, then 2, then 3, ...

And related to this, for the "working normal case", why does the following keep nesting parentheticals?

(define (perm L)
  (if (null? L) '(())
        ; (apply append     <-- why is this part required?
        (map (lambda (elem)
               (map (lambda (other_list) (cons elem other_list))
                    (perm (remove-from-list elem L)))) 
              L)))
          ; )

That is, without doing an (apply append) outside the map, I get the "correct" answer, but with tons of nested parens: (((1 (2 (3))) (1 (3 (2)))) ((2 (1 (3))) (2 (3 (1)))) ((3 (1 (2))) (3 (2 (1))))). I suppose if someone could just show an example of a more basic setup where a map 'telescopes' without the big function that might be helpful.

David542
  • 104,438
  • 178
  • 489
  • 842
  • Not a huge problem, but `(append (list elem) x)` --> `(cons elem x)`. – molbdnilo Jun 23 '21 at 12:01
  • This is three questions: 1. code not working (implying, how to fix it?) 2. can we write it without map, instead? 3. why we get all those nested parens, without append? ---- To your 2., yes, adapting the second way in [this answer](https://stackoverflow.com/a/68060837/849891). To your 3., because append "removes" them, so without append, they remain. – Will Ness Jun 23 '21 at 13:00
  • @WillNess How do the parens come about though in the first place? Also for the answer, it uses `flatmap` which is map/append, or do you mean the 'second' answer? – David542 Jun 23 '21 at 15:52
  • I meant `tuplesND`, at the end of that answer. I've edited it to change `map` to `for-each` since it was used as a looping device, and _`for-each`_ is the proper tool for _that_ (and `map` isn't, since it doesn't guarantee the processing to be done in order, left-to-right on the input list). the result of the function is ignored. – Will Ness Jun 24 '21 at 09:18

1 Answers1

1

Regarding "where do parens come from", it's about types: the function being mapped turns "element" into a "list of elements", so if you map it over a list of elements, you turn each element in the list into a list of elements: ....

[    1,           2,   3, ]   --> 

[ [  1a,   1b ], [2a], [] ]

, say, (in general; not with those functions in question). And since there's recursion there, we then have something like

[ [ [1a1], [] ], [[]], [] ]

, and so on.

So map foo is listof elts -> listof (listof elts):

`foo`     is:             elt  ->        (listof elts)
-------------------------------------------------------
`map foo` is:      listof elts -> listof (listof elts)

But if we apply append after the map on each step, we've leveled it into the listof elts -> listof elts,

`map foo`:         listof elts -> listof (listof elts)
`apply append`:                   listof (listof elts) -> listof elts
----------------------------------------------------------------------
`flatmap foo`:     listof elts                         -> listof elts

and so no new parens are popping up -- since they are leveled at each step when they appear, so they don't accumulate like that; the level of nestedness stays the same.

That's what apply append does: it removes the inner parens:

(apply append [ [x, ...], [y, ...], [z, ...] ] )  ==

(      append   [x, ...]  [y, ...]  [z, ...]   )  == 

              [  x, ...,   y, ...,   z, ...  ]

So, as an example,

> (define (func x) (if (= 0 (remainder x 3)) '() 
    (if (= 0 (remainder x 2)) (list (+ x 1)) 
      (list (+ x 1) (+ x 2)))))

> (display (map func (list 1 2 3 4)))
((2 3) (3) () (5))

> (display (map (lambda (xs) (map func xs)) (map func (list 1 2 3 4))))
(((3) ()) (()) () ((6 7)))

> (display (flatmap func (list 1 2 3 4)))
(2 3 3 5)

> (display (flatmap func (flatmap func (list 1 2 3 4))))
(3 6 7)

Now that the types fit, the flatmap funcs compose nicely, unlike without the flattening. Same happens during recursion in that function. The deeper levels of recursion work on the deeper levels of the result list. And without the flattening this creates more nestedness.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • could you please clarify/explain the first item for `[1,2,3]` -> `[[1a, 1b], [2a], []]` What is it being 'mapped over' here? – David542 Jun 23 '21 at 18:15
  • 1
    some function which produces lists from items. so as an example, for 1 it produces some two-element list, for 2 - one-element list, for 3 - an empty list. and the next step recursion works on those sublists, so the resulting nestedness increases, when we get back to the top. but if we flatten on each step, then no. instead of `[ [ [1a1], [] ], [[]], [] ]` we would get back `[ 1a1 ]`. – Will Ness Jun 23 '21 at 18:29
  • I see, so if it's possible could you show an example with something like `(map (lambda (x) ) '(1 2 3))` with what the `` might be? It's helpful to me as that way I can put it into DrRacket and sort of play around with it and modify things around, but it gives me a nice starting point to investigate if that's ok... – David542 Jun 23 '21 at 18:33
  • 1
    (I've edited the answer to add the examples) – Will Ness Jun 24 '21 at 15:51