Filtering...

cat

books/std/strings/cat
other
(in-package "STR")
other
(include-book "cat-base")
other
(include-book "ieqv")
other
(include-book "std/util/bstar" :dir :system)
other
(include-book "std/lists/list-defuns" :dir :system)
other
(include-book "std/basic/defs" :dir :system)
other
(local (include-book "arithmetic"))
other
(local (include-book "std/lists/equiv" :dir :system))
other
(define append-chars
  ((x :type string) y)
  :parents (concatenation)
  :short "Append a string's characters onto a list."
  :long "<p>@(call append-chars) takes the characters from the string @('x')
and appends them onto @('y').</p>

<p>Its logical definition is nothing more than @('(append (explode x) y)').</p>

<p>In the execution, we traverse the string @('x') using @(see char) to avoid
the overhead of @(see coerce)-ing it into a character list before performing
the @(see append).  This reduces the overhead from @('2n') conses to @('n')
conses, where @('n') is the length of @('x').</p>"
  :inline t
  (mbe :logic (append (explode x) y)
    :exec (b* (((the (integer 0 *) xl) (length x)) ((when (eql xl 0)) y)
        ((the (integer 0 *) n) (- xl 1)))
      (append-chars-aux x n y)))
  :prepwork ((defund append-chars-aux
     (x n y)
     "Appends the characters from x[0:n] onto y"
     (declare (type string x)
       (type (integer 0 *) n)
       (xargs :guard (< n (length x))))
     (if (zp n)
       (cons (char x 0) y)
       (append-chars-aux x
         (the (integer 0 *) (- n 1))
         (cons (char x n) y)))) (local (defthm lemma
        (implies (and (not (zp n)) (<= n (len x)))
          (equal (append (take (- n 1) x)
              (cons (nth (- n 1) x) y))
            (append (take n x) y)))
        :hints (("goal" :in-theory (enable take)
           :induct (take n x)))))
    (defthm append-chars-aux-correct
      (implies (and (stringp x)
          (natp n)
          (< n (length x)))
        (equal (append-chars-aux x n y)
          (append (take (+ 1 n) (explode x))
            y)))
      :hints (("Goal" :in-theory (enable append-chars-aux)
         :induct (append-chars-aux x n y)))))
  ///
  (defthm character-listp-of-append-chars
    (equal (character-listp (append-chars x y))
      (character-listp y)))
  (defcong streqv
    equal
    (append-chars x y)
    1)
  (defcong istreqv
    icharlisteqv
    (append-chars x y)
    1)
  (defcong list-equiv
    list-equiv
    (append-chars x y)
    2)
  (defcong charlisteqv
    charlisteqv
    (append-chars x y)
    2)
  (defcong icharlisteqv
    icharlisteqv
    (append-chars x y)
    2))
other
(defsection revappend-chars
  :extension revappend-chars
  (local (in-theory (enable revappend-chars)))
  (defcong streqv
    equal
    (revappend-chars x y)
    1)
  (defcong istreqv
    icharlisteqv
    (revappend-chars x y)
    1)
  (defcong list-equiv
    list-equiv
    (revappend-chars x y)
    2)
  (defcong charlisteqv
    charlisteqv
    (revappend-chars x y)
    2)
  (defcong icharlisteqv
    icharlisteqv
    (revappend-chars x y)
    2))
other
(define prefix-strings
  ((prefix stringp) (x string-listp))
  :parents (concatenation)
  :short "Concatenates a prefix onto every string in a list of strings."
  :long "<p>@(call prefix-strings) produces a new string list by concatenating
@('prefix') onto every member of @('x').</p>"
  (if (atom x)
    nil
    (cons (cat prefix (car x))
      (prefix-strings prefix (cdr x))))
  ///
  (defthm prefix-strings-when-atom
    (implies (atom x)
      (equal (prefix-strings prefix x) nil)))
  (defthm prefix-strings-of-cons
    (equal (prefix-strings prefix (cons a x))
      (cons (cat prefix a)
        (prefix-strings prefix x))))
  (defthm string-listp-of-prefix-strings
    (string-listp (prefix-strings prefix x)))
  (defthm len-of-prefix-strings
    (equal (len (prefix-strings prefix x))
      (len x)))
  (defcong streqv
    equal
    (prefix-strings prefix x)
    1)
  (local (defthmd l0
      (equal (prefix-strings prefix (list-fix x))
        (prefix-strings prefix x))))
  (defcong list-equiv
    equal
    (prefix-strings prefix x)
    2
    :hints (("Goal" :in-theory (enable list-equiv)
       :use ((:instance l0 (x x)) (:instance l0 (x x-equiv)))))))
other
(define join
  ((x string-listp) (separator :type string))
  :returns (joined stringp :rule-classes :type-prescription)
  :parents (concatenation)
  :short "Concatenate a list of strings with some separator between."
  :long "<p>@(call join) joins together the list of strings @('x'), inserting
the string @('separator') between the members.  For example:</p>

@({
 (join '("a" "b" "c") ".") = "a.b.c"
 (join '("a" "b" "c") "->") = "a->b->c"
})

<p>We always return a string; an empty @('x') results in the empty string, and
any empty strings within @('x') just implicitly don't contribute to the
result.</p>

<p>Any sort of string concatenation is slow, but @('join') is reasonably
efficient: it creates a single character list for the result (in reverse order)
without any use of @(see coerce), then uses @(see rchars-to-string) to build
and reverse the result string.</p>"
  :prepwork ((defund join-aux
     (x separator acc)
     (declare (xargs :guard (string-listp x))
       (type string separator))
     (cond ((atom x) acc)
       ((atom (cdr x)) (revappend-chars (car x) acc))
       (t (let* ((acc (revappend-chars (car x) acc)) (acc (revappend-chars separator acc)))
           (join-aux (cdr x) separator acc))))))
  :inline t
  :verify-guards nil
  (mbe :logic (cond ((atom x) "")
      ((atom (cdr x)) (str-fix (car x)))
      (t (cat (car x)
          separator
          (join (cdr x) separator))))
    :exec (rchars-to-string (join-aux x separator nil)))
  ///
  (local (in-theory (enable join-aux)))
  (defthm join-aux-removal
    (implies (and (string-listp x) (stringp separator))
      (equal (join-aux x separator acc)
        (revappend (coerce (join x separator) 'list)
          acc)))
    :hints (("Goal" :induct (join-aux x separator acc)
       :in-theory (enable revappend-chars))))
  (verify-guards join$inline
    :hints (("Goal" :in-theory (enable join join-aux))))
  (local (defthmd l0
      (equal (join (list-fix x) separator)
        (join x separator))))
  (defcong list-equiv
    equal
    (join x separator)
    1
    :hints (("Goal" :in-theory (enable list-equiv)
       :use ((:instance l0 (x x)) (:instance l0 (x x-equiv))))))
  (defcong streqv
    equal
    (join x separator)
    2)
  (defcong istreqv
    istreqv
    (join x separator)
    2))