Question

I'll explain in math, here's the transformation I'm struggling to write Scheme code for:

(f '(a b c) '(d e f)) = '(ad (+ bd ae) (+ cd be af) (+ ce bf) cf)

Where two letters together like ad means (* a d).

I'm trying to write it in a purely functional manner, but I'm struggling to see how. Any suggestions would be greatly appreciated.

Here are some examples:

(1mul '(0 1) '(0 1)) = '(0 0 1)
(1mul '(1 2 3) '(1 1)) = '(1 3 5 3)
(1mul '(1 2 3) '(1 2)) = '(1 4 7 6)
(1mul '(1 2 3) '(2 1)) = '(2 5 8 3)
(1mul '(1 2 3) '(2 2)) = '(2 6 10 6)
(1mul '(5 5 5) '(1 1)) = '(5 10 10 5)
(1mul '(0 0 1) '(2 5)) = '(0 0 2 5)
(1mul '(1 1 2 3) '(2 5)) = '(2 7 9 16 15)

So, the pattern is like what I posted at the beginning:

Multiply the first number in the list by every number in the second list (ad, ae, af) and then continue along, (bd, be, bf, cd, ce, cf) and arrange the numbers "somehow" to add the corresponding values. The reason I call it overlapping is because you can sort of visualize it like this:

(list
       aa'
    (+ ba' ab')
    (+ ca' bb' ac')
        (+ cb' bc')
               cc')

Again,

(f '(a b c) '(d e f)) = '(ad (+ bd ae) (+ cd be af) (+ ce bf) cf)

However, not just for 3x3 lists, for any sized lists.

Was it helpful?

Solution

Here's my code. It's in racket

#lang racket

(define (drop n xs)
  (cond [(<= n 0) xs]
        [(empty? xs) '()]
        [else (drop (sub1 n) (rest xs))]))        

(define (take n xs)
  (cond [(<= n 0) '()]
        [(empty? xs) '()]
        [else (cons (first xs) (take (sub1 n) (rest xs)))]))        


(define (mult as bs)
  (define (*- a b)
    (list '* a b))
  (define degree (length as))
  (append 
   (for/list ([i  (in-range 1 (+ 1 degree))])
     (cons '+ (map *- (take i as) (reverse (take i bs)))))
   (for/list ([i  (in-range 1 degree)])
     (cons '+ (map *- (drop i as) (reverse (drop i bs)))))))

The for/lists are just ways of mapping over a list of numbers and collecting the result in a list. If you need, I can reformulate it just maps.

OTHER TIPS

Is this a good candidate for recursion? Not sure, but here's a a direct translation of what you asked for.

(define (f abc def)
  (let ((a (car abc)) (b (cadr abc)) (c (caddr abc))
        (d (car def)) (e (cadr def)) (f (caddr def)))
    (list (* a d)
          (+ (* b d) (* a e))
          (+ (* c d) (* b e) (* a f))
          (+ (* c e) (* b f))
          (* c f))))

Is it correct to assume, that you want to do this computation?

(a+b+c)*(d+e+f) = a(d+e+f) + b(d+e+f) + c(d+e+f) 
                = ad+ae+af + bd+be+bf + cd+ce+cf

If so, this is simple:

(define (f xs ys)
   (* (apply + xs) (apply + ys))

If you are interested in the symbolic version:

#lang racket
(define (f xs ys)
  (define (fx x)
    (define (fxy y)
      (list '* x y))
    (cons '+ (map fxy ys)))
  (cons '+ (map fx xs)))

And here is a test:

> (f '(a b c) '(d e f))
'(+ (+ (* a d) (* a e) (* a f)) 
    (+ (* b d) (* b e) (* b f)) 
    (+ (* c d) (* c e) (* c f)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top