Search code examples
listschemeracketcdr

Functions to print and replace elements in a list


I am trying to implement two functions : subterm and replace.

  1. subterm takes two lists as arguments and prints the element in the first list that is reached after exhausting the second list.

For example, calling

(subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(4 2 2 1))

should return

8

I have come up with the following function which prints the nth element in the list :

(define (subterm list n)                   
  (cond 
    ((null? list) '())             
    ((= n 1) (car list))              
    (else (subterm (cdr list) (- n 1)))))
  1. replace takes 3 lists and returns the result of replacing the reached value with the rest of the list unchanged.

for example calling :

 (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(11 12) '(4 2 2 1))

should return :

'(1 2 (3 4 5) (6 (7 ((11 12)) 9 10)))

Again, I came up with this code which replaces the nth element in the first list with the second list, leaving the rest of the first list unchanged :

#lang racket
(define (replace list elem n)
  (cond
    ((empty? list) empty)
    ((eq? n 1) (cons elem (cdr list)))
    (#t (cons (car list) (replace (cdr list) elem (- n 1))))))

How do I modify these functions to take in two lists?

Edit 1: Some examples:

> (subterm '(1 2 3 4 5) '(3))
3

> (subterm '(1 2 3 4 5) '(2))
2

> (subterm '(1 2 (3 4 5) 6 7) '(3 2))
4

Consider this example:

> (subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(4 2 2 1))
8

In the above example, subterm takes 2 lists. Then it reads the second list. The second list basically tells subterm to return the 1st element (8) of the 2nd element ((8)) of the 2nd element (7 (8) 9 10) of the 4th element (6 (7 (8) 9 10) of the first list (1 2 (3 4 5) (6 (7 (8) 9 10))).

> (subterm '1 '())
1

> (subterm '(1 2 (3 4 5) (6 (7 (8) 9 10))) '())
'(1 2 (3 4 5) (6 (7 (8) 9 10)))

> (replace '(1 2 3 4 5) '(6 7 8) '(3))
'(1 2 (6 7 8) 4 5)

> (replace '(1 2 3 4 5) '(6 7 8) '(2))
'(1 (6 7 8) 3 4 5)

Consider this example:

> (replace '(1 2 (3 4 5) 6 7) '(8 9) '(3 2))
'(1 2 (3 (8 9) 5) 6 7)

replace takes in three lists: first list is the list in which elements have to be replaced. The second list contains the new elements which have to be put into the first list. The third list contains the positions where the elements have to be replaced. So, it basically replaced the 2nd element (4) of the 3rd element (3 4 5) of the first list (1 2 (3 4 5) 6 7).

> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) '(11 12) '(4 2 2 1))
'(1 2 (3 4 5) (6 (7 ((11 12)) 9 10)))

> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 1000 '(4 2 2 1))
'(1 2 (3 4 5) (6 (7 (1000) 9 10)))

> (replace '(1 2 (3 4 5) (6 (7 (8) 9 10))) 'x '())
'x

> (replace '1 '(2 3 4) '())
'(2 3 4)

Solution

  • First of all, you're using the name subterm for two different functions. Let's call the version you provided a code example for list-ref, and make the (car list) case happen when n = 0 instead of 1:

    (define (list-ref list n)                   
      (cond 
        ((null? list) '())             
        ((= n 0) (car list))              
        (else (list-ref (cdr list) (- n 1)))))
    

    As it turns out, list-ref is already in the racket library, so you shouldn't really have to implement it in the first place. So using that, your subterm is trivial:

    (define (subterm main-list path)
       (match path
         ('() #f)
         ((list n) (list-ref main-list (sub1 n)))
         ((cons n rest) (subterm (list-ref main-list (sub1 n)) rest))))