Next: , Previous: , Up: srfi strings spec   [Index]


2.8.3.12 Fold, unfold and map

Function: string-map proc str
Function: string-map proc str start
Function: string-map proc str start end

proc is a char–to–char procedure and it is mapped over the selected substring of str; return the result string and does not alter its str parameter.

NOTE The order in which proc is applied to the elements of str is not specified.

Function: string-map! proc str
Function: string-map! proc str start
Function: string-map! proc str start end

In–place side–effecting variant.

Function: string-for-each proc str
Function: string-for-each proc str start
Function: string-for-each proc str start end

Apply proc to each character in str from start to end in increasing order. Return unspecified values.

Function: string-for-each-index proc str
Function: string-for-each-index proc str start
Function: string-for-each-index proc str start end

Apply proc to each index of the selected substring of str, in increasing order from start to end. This is simply a method of looping over a string that is guaranteed to be safe and correct. Example:

(let* ((len (string-length s))
       (ans (make-string len)))
  (string-for-each-index
    (lambda (i)
      (string-set! ans (- len i) (string-ref s i)))
    s)
  ans)
Function: string-fold kons knil str
Function: string-fold kons knil str start
Function: string-fold kons knil str start end
Function: string-fold-right kons knil str
Function: string-fold-right kons knil str start
Function: string-fold-right kons knil str start end

These are the fundamental iterators for strings.

The left–fold operator maps the kons procedure across the string from left to right:

(... (kons s[2] (kons s[1] (kons s[0] knil))))

in other words, string-fold obeys the (tail) recursion:

(string-fold kons knil s start end)
≡ (string-fold kons (kons s[start] knil) start+1 end)

The right–fold operator maps the kons procedure across the string from right to left:

(kons s[0]
      (... (kons s[end-3]
                 (kons s[end-2]
                       (kons s[end-1] knil)))))

obeying the (tail) recursion:

(string-fold-right kons knil s start end)
≡ (string-fold-right kons (kons s[end-1] knil) start end-1)

Examples:

;;; Convert a string to a list of chars.
(string-fold-right cons '() s)

;;; Count the number of lower-case characters in a string.
(string-fold (lambda (c count)
               (if (char-lower-case? c)
                   (+ count 1)
                 count))
              0
              s)

;;; Double every backslash character in S.
(let* ((ans-len (string-fold (lambda (c sum)
                               (+ sum (if (char=? c #\\)
                                          2
                                        1)))
                             0 s))
       (ans     (make-string ans-len)))
  (string-fold (lambda (c i)
                 (let ((i (if (char=? c #\\)
                              (begin
                                (string-set! ans i #\\)
                                (+ i 1))
                            i)))
                    (string-set! ans i c)
                    (+ i 1)))
               0 s)
  ans)

The right–fold combinator is sometimes called a “catamorphism”.

Function: string-unfold stop? seed->char make-seed first-seed
Function: string-unfold stop? seed->char make-seed first-seed base-str
Function: string-unfold stop? seed->char make-seed first-seed base-str make-final

This is a fundamental constructor for strings.

make-seed

Is used to generate a series of “seed” values from the initial seed:

first-seed
(make-seed first-seed)      ⇒ seed2
(make-seed seed2)           ⇒ seed3
(make-seed seed3)           ⇒ seed4
...
stop?

Tells us when to stop; when it returns true when applied to one of the seed values.

seed->char

Maps each seed value to the corresponding character in the result string. These chars are assembled into the string in a left–to–right order.

base-string

Is the optional initial/leftmost portion of the constructed string; it defaults to the empty string.

make-final

Is applied to the terminal seed value (on which stop? returns true) to produce the final/rightmost portion of the constructed string. It defaults to:

(lambda (x) "")

More precisely, the following (simple, inefficient) definitions hold:

;;; Iterative
(define (string-unfold stop? seed->char make-seed
                       first-seed base-str make-final)
  (let loop ((seed first-seed)
             (ans  base-str))
    (if (stop? seed)
        (string-append ans (make-final seed))
      (loop (make-seed seed)
            (string-append ans (string (seed->char seed)))))))

;;; Recursive
(define (string-unfold stop? seed->char make-seed
                       first-seed base-str make-final)
  (string-append
     base-str
     (let recur ((seed first-seed))
       (if (stop? seed)
           (make-final seed)
         (string-append (string (seed->char seed))
                        (recur  (make-seed  seed)))))))

string-unfold is a fairly powerful string constructor; we can use it to convert a list to a string, read a port into a string, reverse a string, copy a string, and so forth. Examples:

(port->string p)
≡ (string-unfold eof-object? values
             (lambda (x) (read-char p))
             (read-char p))

(list->string lis)
≡ (string-unfold null? car cdr lis)

(string-tabulate f size)
≡ (string-unfold
             (lambda (i) (= i size))
             f add1 0)

to map seed->char over a list lis, producing a string:

(string-unfold null? (compose f car) cdr lis)

Interested functional programmers may enjoy noting that string-fold-right and string-unfold are in some sense inverses. That is, given operations knull?, kar, kdr, kons, and knil satisfying:

(kons (kar x) (kdr x))  ≡ x
(knull? knil)           ≡ #t

then:

(string-fold-right kons knil
   (string-unfold knull? kar kdr x))
≡ x

and:

(string-unfold knull? kar kdr
   (string-fold-right kons knil s))
≡ s

The final string constructed does not share storage with either base-str or the value produced by make-final.

This combinator sometimes is called an “anamorphism”.

Function: string-unfold-right stop? seed->char make-seed first-seed
Function: string-unfold-right stop? seed->char make-seed first-seed base-str
Function: string-unfold-right stop? seed->char make-seed first-seed base-str make-final

This is a fundamental constructor for strings.

make-seed

Is used to generate a series of “seed” values from the initial first-seed:

first-seed
(make-seed first-seed)      ⇒ seed2
(make-seed seed2)           ⇒ seed3
(make-seed seed3)           ⇒ seed4
...
stop?

Tells us when to stop; when it returns true when applied to one of these seed values.

seed->char

Maps each seed value to the corresponding character in the result string. These chars are assembled into the string in a right–to–left order.

base-str

Is the optional initial/rightmost portion of the constructed string; it defaults to the empty string.

make-final

Is applied to the terminal seed value (on which stop? returns true) to produce the final/leftmost portion of the constructed string. It defaults to:

(lambda (x) "")

More precisely, the following (simple, inefficient) definitions hold:

;;; Iterative
(define (string-unfold-right stop? seed->char make-seed
                             first-seed base-str make-final)
  (let loop ((seed first-seed)
             (ans  base-str))
    (if (stop? seed)
        (string-append (make-final seed) ans)
      (loop (make-seed seed)
            (string-append (string (seed->char seed)) ans)))))

;;; Recursive
(define (string-unfold-right stop? seed->char make-seed
                             first-seed base-str make-final)
  (string-append
     (let recur ((seed first-seed))
       (if (stop? seed)
           (make-final seed)
         (string-append (recur  (make-seed  seed))
                        (string (seed->char seed)))))
     base-str))

Interested functional programmers may enjoy noting that string-fold and string-unfold-right are in some sense inverses. That is, given operations knull?, kar, kdr, kons, and knil satisfying:

(kons (kar x) (kdr x))  ≡ x
(knull? knil)           ≡ #t

then:

(string-fold kons knil
  (string-unfold-right knull? kar kdr x))
≡ x

and:

(string-unfold-right knull? kar kdr
  (string-fold kons knil s))
≡ s

The final string constructed does not share storage with either base-str or the value produced by make-final.


Next: , Previous: , Up: srfi strings spec   [Index]