3

Hi all I am new at learning Scheme and often have issues with making parallels between an imperative language and a functional language.

For example if I had had two arrays.

A = [1 2 3]
B = [4 5 6]

If I wanted to create a new array with the elements of A multiplied by each element in B I could simply do something like (pseudo-code):

for(int i = 0; i < A.length; i++)
    for(int j = 0; j < B.length, j++)
        arr.push(A[i]*B[j])

Which would give back:

arr = [4 5 6 8 10 12 12 15 18]

What would be some ways to approach this problem in a functional language?

Abdall
  • 455
  • 1
  • 6
  • 15
  • For a *zip* of two lists of equal length, `(map * (list 1 2 3 4) (list 5 6 7 8))` is `(5 12 21 32)` in Scheme. In Haskell, `zipWith (*) [1,2,3,4] [5,6,7,8]` `==` `[5,12,21,32]`. –  Apr 20 '17 at 21:05

2 Answers2

4

In Scheme, the most common data structure is the linked list. Unless you have to access elements by index, it's always preferred to use lists, as there are countless built-in procedures for handling lists, that make easy to implement most algorithms without ever using an index. Just remember that for efficient access by index, using a vector would be a better idea.

Having said that, and depending on the Scheme dialect that you're using, the solution can be as simple as this (in Racket, see the documentation):

(define a '(1 2 3))
(define b '(4 5 6))

(for*/list ([x a] [y b])
  (* x y))

=> '(4 5 6 8 10 12 12 15 18)

Alternatively, using only standard Scheme:

(apply append
       (map (lambda (x)
              (map (lambda (y) (* x y))
                   b))
            a))
Óscar López
  • 232,561
  • 37
  • 312
  • 386
0

In Scheme and Racket arrays (array: a data structure indexed by a natural number) is represented using vectors.

(define as  (vector 1 2 3))
(define bs  (vector 4 5 6))

To make a loop-inside-a-loop we will use a variant of for*. Plain for* works like this:

(for* ([a as] [b bs])
   (displayln (* a b))))

Here a runs through the elements of the vector as and b runs through the elements in bs. Since for* is used, the b-loop runs inside the a-loop. If for is used instead the loops run in parallel (try it).

Now since we want to collect the element, we can use for*/vector which stores the generated elements in a vector:

(for*/vector ([a as] [b bs])
  (* a b)))

For efficiency reason, one can write:

(for*/vector ([a (in-vector as)] [b (in-vector bs)])
  (* a b)))

This will generate sligthly more efficient code.

However

(for*/vector ([a as] [b bs])
  (* a b)))

will also work if as and bs are lists.

soegaard
  • 30,661
  • 4
  • 57
  • 106