semantics/beginner-funs.rkt
(module beginner-funs racket/base
  (require syntax/docprovide)
  (require "wrap-prim.rkt")
  (require (prefix-in racket: (only-in racket/base

                                       + - * / < <= = >= >

                                       number? max min quotient remainder modulo
                                       sqrt integer-sqrt expt abs exp log
                                       sin cos tan asin acos atan
                                       exact? integer? zero? positive? negative? odd? even?
                                       add1 sub1
                                       lcm gcd rational? numerator denominator inexact? real?
                                       floor ceiling round
                                       complex? make-polar make-rectangular real-part imag-part
                                       magnitude angle
                                       inexact->exact exact->inexact
                                       number->string integer->char random current-seconds

                                       boolean? not

                                       append assq cons list? list list-ref member remove

                                       string? string-length string-ref substring string-append
                                       string<? string<=? string=? string>=? string>?
                                       string-ci<? string-ci<=? string-ci=? string-ci>=? string-ci>?
                                       string->number

                                       equal? eof-object?
                              )
           )
           (prefix-in racket: (only-in racket/math
                                       sqr sgn sinh cosh conjugate
                              )
           )
           (prefix-in racket: (only-in lang/htdp-intermediate
                                       replicate explode implode string-numeric?
                                       string-alphabetic? string-whitespace?
                                       string-upper-case? string-lower-case?

                                       error exit =~))
           (prefix-in racket: (only-in racket/bool boolean=? false?))
           (prefix-in racket: racket/list)
           (prefix-in racket: lang/posn)
  )
  (require (only-in lang/htdp-beginner e pi))
  (require "../utilities.rkt")

  (define (integer->string i)
    (when (or (< i 0)
              (> i #x10FFFF))
      (error-bad-arg "integer_to_string"
                     "expected the argument to be between 0, and 0x10FFFF, inclusive"
                     1))
    (string (integer->char i)))
  
  (define (string_ith s i)
    (let ([len (racket:string-length s)])
      (when (>= i len)
        (error-bad-arg "string_ref"
                       (format "given an index of ~a, but the string is only ~a characters long"
                               i
                               len)))
      (string (string-ref s i))))
                 

  ;; --------------------------------------------------------------------
  ;; numbers
  ;; --------------------------------------------------------------------
  (wrap + racket:+ (at-least 1) (list number-sig))
  (wrap - racket:- (at-least 1) (list number-sig))
  (wrap * racket:* (at-least 1) (list number-sig))
  (wrap / racket:/ (at-least 1) (list number-sig))
  (wrap < racket:< (at-least 2) (list number-sig number-sig))
  (wrap <= racket:<= (at-least 2) (list number-sig number-sig))
  (wrap = racket:= (at-least 2) (list number-sig number-sig))
  (wrap >= racket:>= (at-least 2) (list number-sig number-sig))
  (wrap > racket:> (at-least 2) (list number-sig number-sig))
  (wrap is_number racket:number? (exactly 1) (list any-sig))
  (wrap max racket:max (at-least 1) (list real-sig))
  (wrap min racket:min (at-least 1) (list real-sig))
  (wrap quotient racket:quotient (exactly 2) (list integer-sig integer-sig))
  (wrap remainder racket:remainder (exactly 2) (list integer-sig integer-sig))
  (wrap modulo racket:modulo (exactly 2) (list integer-sig integer-sig))
  (wrap sqr racket:sqr (exactly 1) (list number-sig))
  (wrap sqrt racket:sqrt (exactly 1) (list number-sig))
  (wrap integer_sqrt racket:integer-sqrt (exactly 1) (list integer-sig))
  (wrap expt racket:expt (exactly 2) (list number-sig number-sig))
  (wrap abs racket:abs (exactly 1) (list real-sig))
  (wrap sgn racket:sgn (exactly 1) (list real-sig))
  
  ;; fancy numeric
  (wrap exp racket:exp (exactly 1) (list number-sig))
  (wrap log racket:log (exactly 1) (list number-sig))
  
  ;; trig
  (wrap sin racket:sin (exactly 1) (list number-sig))
  (wrap cos racket:cos (exactly 1) (list number-sig))
  (wrap tan racket:tan (exactly 1) (list number-sig))
  (wrap asin racket:asin (exactly 1) (list number-sig))
  (wrap acos racket:acos (exactly 1) (list number-sig))
  (wrap atan racket:atan (exactly 1) (list number-sig))
  
  ;; hyperbolics
  (wrap sinh racket:sinh (exactly 1) (list number-sig))
  (wrap cosh racket:cosh (exactly 1) (list number-sig))
  
  ;; predicates
  (wrap is_exact racket:exact? (exactly 1) (list number-sig))
  (wrap is_integer racket:integer? (exactly 1) (list any-sig))
  (wrap is_zero racket:zero? (exactly 1) (list number-sig))
  (wrap is_positive racket:positive? (exactly 1) (list real-sig))
  (wrap is_negative racket:negative? (exactly 1) (list real-sig))
  (wrap is_even racket:even? (exactly 1) (list integer-sig))
  (wrap is_odd racket:odd? (exactly 1) (list integer-sig))
  
  ;; add1 and sub1
  (wrap add1 racket:add1 (exactly 1) (list number-sig))
  (wrap sub1 racket:sub1 (exactly 1) (list number-sig))
  
  ;; decimals and inexact/exact
  (wrap lcm racket:lcm (at-least 1) (list number-sig number-sig))
  (wrap gcd racket:gcd (at-least 1) (list number-sig number-sig))
  (wrap is_rational racket:rational? (exactly 1) (list any-sig))
  (wrap numerator racket:numerator (exactly 1) (list rat-sig))
  (wrap denominator racket:denominator (exactly 1) (list rat-sig))
  (wrap is_inexact racket:inexact? (exactly 1) (list number-sig))
  (wrap is_real racket:real? (exactly 1) (list any-sig))
  (wrap floor racket:floor (exactly 1) (list real-sig))
  (wrap ceiling racket:ceiling (exactly 1) (list real-sig))
  (wrap round racket:round (exactly 1) (list real-sig))
  
  ;; complex numbers
  (wrap is_complex racket:complex? (exactly 1) (list any-sig))
  (wrap make_rectangular racket:make-rectangular (exactly 2) (list real-sig real-sig))
  (wrap make_polar racket:make-polar (exactly 2) (list real-sig real-sig))
  (wrap real_part racket:real-part (exactly 1) (list number-sig))
  (wrap imag_part racket:imag-part (exactly 1) (list number-sig))
  (wrap magnitude racket:magnitude (exactly 1) (list number-sig))
  (wrap angle racket:angle (exactly 1) (list number-sig))
  (wrap conjugate racket:conjugate (exactly 1) (list number-sig))
  (wrap inexact_to_exact racket:inexact->exact (exactly 1) (list number-sig))
  (wrap exact_to_inexact racket:exact->inexact (exactly 1) (list number-sig))
  
  ;; odds and ends
  (wrap number_to_string racket:number->string (exactly 1) (list number-sig))
  (wrap integer_to_string integer->string (exactly 1) (list integer-sig))
  (wrap random racket:random (exactly 1) (list integer-sig))
  (wrap current_seconds racket:current-seconds (exactly 0) '())

  ;; ---------------------------------------------------------------------------
  ;; Booleans
  ;; ---------------------------------------------------------------------------
  (wrap boolean_equal racket:boolean=? (exactly 2) (list boolean-sig boolean-sig))
  (wrap is_boolean racket:boolean? (exactly 1) (list any-sig))
  (wrap is_false racket:false? (exactly 1) (list any-sig))
  (wrap not racket:not (exactly 1) (list boolean-sig))

  ;; ---------------------------------------------------------------------------
  ;; Lists
  ;; ---------------------------------------------------------------------------
  (wrap append racket:append (at-least 2) (list list-sig list-sig))
  (wrap assq racket:assq (exactly 2) (list any-sig list-sig))
  (wrap cons racket:cons (exactly 2) (list any-sig list-sig))
  (wrap is_list racket:list? (exactly 1) (list any-sig))
  ; we will let the built-in versions of these check to make sure there are
  ; enough elements -- this is ok, since their names consist purely of
  ; alphabetic characters
  (wrap first racket:first (exactly 1) (list list-sig))
  (wrap second racket:second (exactly 1) (list list-sig))
  (wrap third racket:third (exactly 1) (list list-sig))
  (wrap fourth racket:fourth (exactly 1) (list list-sig))
  (wrap fifth racket:fifth (exactly 1) (list list-sig))
  (wrap sixth racket:sixth (exactly 1) (list list-sig))
  (wrap seventh racket:seventh (exactly 1) (list list-sig))
  (wrap eighth racket:eighth (exactly 1) (list list-sig))
  (wrap rest racket:rest (exactly 1) (list list-sig))
  ;
  (wrap internal-list racket:list (variable) (list any-sig))
  (wrap list_ref racket:list-ref (exactly 2) (list list-sig nonnegative-sig))
  (wrap make_list racket:make-list (exactly 2) (list nonnegative-sig any-sig))
  (wrap member 
        (lambda args 
          (let ([result (apply racket:member args)])
            (if result
                #t
                #f)))
        (exactly 2) 
        (list any-sig list-sig))
  (wrap remove racket:remove (exactly 2) (list any-sig list-sig))
  (wrap is_null racket:empty? (exactly 1) (list any-sig))
  (wrap is_empty racket:empty? (exactly 1) (list any-sig))

  ;; ---------------------------------------------------------------------------
  ;; posns
  ;; ---------------------------------------------------------------------------
  (wrap posn racket:make-posn (exactly 2) (list number-sig number-sig))
  (wrap is_posn racket:posn? (exactly 1) (list any-sig))
  
  ;; ---------------------------------------------------------------------------
  ;; Strings
  ;; ---------------------------------------------------------------------------
  (wrap is_string racket:string? (exactly 1) (list any-sig))
  (wrap string_length racket:string-length (exactly 1) (list string-sig))

  (wrap string_ref string_ith (exactly 2) (list string-sig nonnegative-sig))
  (wrap replicate racket:replicate (exactly 2) (list nonnegative-sig string-sig))
  (wrap explode racket:explode (exactly 1) (list string-sig))
  (wrap implode racket:implode (exactly 1) (list list-sig))
  (wrap int_to_string integer->string (exactly 1) (list integer-sig))
  (wrap string_is_numeric racket:string-numeric? (exactly 1) (list string-sig))
  (wrap string_is_alphabetic racket:string-alphabetic? (exactly 1) (list string-sig))
  (wrap string_is_whitespace racket:string-whitespace? (exactly 1) (list string-sig))
  (wrap string_is_upper_case racket:string-upper-case? (exactly 1) (list string-sig))
  (wrap string_is_lower_case racket:string-lower-case? (exactly 1) (list string-sig))

  (wrap substring racket:substring (exactly 3) (list string-sig
                                                     nonnegative-sig
                                                     nonnegative-sig))
  (wrap string_append racket:string-append (variable) (list string-sig))

  (wrap string_lt racket:string<? (at-least 2) (list string-sig string-sig))
  (wrap string_leq racket:string<=? (at-least 2) (list string-sig string-sig))
  (wrap string_equal racket:string=? (at-least 2) (list string-sig string-sig))
  (wrap string_geq racket:string>=? (at-least 2) (list string-sig string-sig))
  (wrap string_gt racket:string>? (at-least 2) (list string-sig string-sig))

  (wrap string_ci_lt racket:string-ci<? (at-least 2) (list string-sig string-sig))
  (wrap string_ci_leq racket:string-ci<=? (at-least 2) (list string-sig string-sig))
  (wrap string_ci_equal racket:string-ci=? (at-least 2) (list string-sig string-sig))
  (wrap string_ci_geq racket:string-ci>=? (at-least 2) (list string-sig string-sig))
  (wrap string_ci_gt racket:string-ci>? (at-least 2) (list string-sig string-sig))

  (wrap string_to_number racket:string->number (exactly 1) (list string-sig))

  ;; ---------------------------------------------------------------------------
  ;; Misc.
  ;; ---------------------------------------------------------------------------
  (wrap identity (lambda (x) x) (exactly 1) (list any-sig))
  (wrap error racket:error (at-least 1) (list any-sig))
  (wrap equal racket:equal? (exactly 2) (list any-sig any-sig))
  (wrap approx_equal racket:=~ (exactly 3) (list number-sig number-sig nonnegative-sig))
  (wrap is_eof_object eof-object? (exactly 1) (list any-sig))
  (wrap exit racket:exit (exactly 0) '())
  
  ;; ---------------------------------------------------------------------------
  ;; procedures with documentation:
  ;; ---------------------------------------------------------------------------
  (provide-and-document
    procedures

    ("Numbers: Integers, Rationals, Reals, Complex, Exacts, Inexacts"
      (is_number (any -> boolean)
        "Determines whether some value is a number.")
      (=  (number number -> boolean)
          "Compares numbers for equality.")
      (<  (real real -> boolean)
          "Compares real numbers for less-than.")
      (>  (real real real ... -> boolean)
         "Compares real numbers for greater-than.")
      (<= (real real real ... -> boolean)
          "Compares real numbers for less-than or equality.")
      (>= (real real real ... -> boolean)
          "Compares real numbers for greater-than or equality.")
    
      (+ (number number number ... -> number)
       "Evaluates the sum of the input numbers.")
      (- (number number ... -> number)
         "subtracts the second (and following) number(s) from the first; negate the number if there is only one argument.")
      (* (number number number ... -> number)
       "Evaluates the product of all of the input numbers.")
      (/ (number number number ... -> number)
       "Divides the first by the second (and all following) number(s); try (/ 3 4) and (/ 3 2 2)"
       " only the first number can be zero.")
      (max (real real ... -> real)
        "Determines the largest number.")
      (min (real real ... -> real)
        "Determines the smallest number.")       
      (quotient (integer integer -> integer)
        "Divides the first integer (exact or inexact) into the second; try (quotient 3 4) and (quotient 4 3).")
      (remainder (integer integer -> integer)
        "Determines the remainder of dividing the first by the second integer (exact or inexact).")
      (modulo (integer integer -> integer)
        "Finds the remainder of the division of the first number by the second; try (modulo 4 3) (modulo 4 -3).") 
      (sqr (number -> number)
        "Evaluates the square of a number.")
      (sqrt (number -> number)
        "Evaluates the square root of a number.")
      (integer_sqrt (integer -> integer)
        "Evaluates the integer (exact or inexact) square root of a number.")      
      (expt (number number -> number)
        "Evaluates the power of the first to the second number.")
      (abs (real -> real)
        "Evaluates the absolute value of a real number.")
      (sgn (real -> (union 1 #i1.0 0 #i0.0 -1 #i-1.0))
        "Evaluates the sign of a real number.")
    
      ;; fancy numeric
      (exp (number -> number)
        "Evaluates e raised to a number.")
      (log (number -> number)
        "Evaluates the base-e logarithm of a number.")
    
      ;; trigonometry
      (sin (number -> number)
        "Evaluates the sine of a number (radians).")
      (cos (number -> number)
        "Evaluates the cosine of a number (radians).")
      (tan (number -> number)
        "Evaluates the tangent of a number (radians).")
      (asin (number -> number)
        "Evaluates the arcsine (inverse of sin) of a number.")
      (acos (number -> number)
        "Evaluates the arccosine (inverse of cos) of a number.")
      (atan (number [number] -> number)
        "Evaluates the arctan of the given number or the ratio of the two given numbers.")    
    
      (sinh (number -> number)
        "Evaluates the hyperbolic sine of a number.")
      (cosh (number -> number)
        "Evaluates the hyperbolic cosine of a number.")
    
      (is_exact (number -> boolean)
        "Determines whether some number is exact.")
    
      (is_integer (any -> boolean)
        "Determines whether some value is an integer (exact or inexact).")
    
      (is_zero (number -> boolean)
        "Determines if some value is zero or not.") 
      (is_positive (number -> boolean)
        "Determines if some value is strictly larger than zero.")
      (is_negative (number -> boolean)
        "Determines if some value is strictly smaller than zero.")      
      (is_odd (integer -> boolean)
        "Determines if some integer (exact or inexact) is odd or not.")
      (is_even (integer -> boolean)
        "Determines if some integer (exact or inexact) is even or not.")

      (add1 (number -> number)
        "Evaluates a number one larger than a given number.")
      (sub1 (number -> number)
        "Evaluates a number one smaller than a given number.")

      (lcm (integer integer ... -> integer)
        "Evaluates the least common multiple of two integers (exact or inexact).")
    
      (gcd (integer integer ... -> integer)
        "Evaluates the greatest common divisior of two integers (exact or inexact).")
    
      (is_rational (any -> boolean)
        "Determines whether some value is a rational number.")
    
      (numerator (rat -> integer)
        "Evaluates the numerator of a rational.")
    
      (denominator (rat -> integer)
        "Evaluates the denominator of a rational.")
    
      (is_inexact (number -> boolean)
        "Determines whether some number is inexact.")
    
      (is_real (any -> boolean)
        "Determines whether some value is a real number.")
    
      (floor (real -> integer)
        "Determines the closest integer (exact or inexact) below a real number.")
    
      (ceiling (real -> integer)
        "Determines the closest integer (exact or inexact) above a real number.")
    
      (round (real -> integer)
        "Rounds a real number to an integer (rounds to even to break ties).")
    
      (is_complex (any -> boolean)
        "Determines whether some value is complex.")
    
      (make_polar (real real -> number)
        "Creates a complex from a magnitude and angle.")

      (make_rectangular (real real -> number)
        "Creates a complex from a real and an imaginary part.")
    
      (real_part (number -> real)
        "Extracts the real part from a complex number.")
    
      (imag_part (number -> real)
        "Extracts the imaginary part from a complex number.")
    
      (magnitude (number -> real)
        "Determines the magnitude of a complex number.")
    
      (angle (number -> real)
        "Extracts the angle from a complex number.")
    
      (conjugate (number -> number)
        "Evaluates the conjugate of a complex number.")
    
      (exact_to_inexact (number -> number)
        "Converts an exact number to an inexact one.")
    
      (inexact_to_exact (number -> number)
        "Approximates an inexact number by an exact one.")
    
      ;    "Odds and ends"
    
      (number_to_string (number -> string)
        "Converts a number to a string.")
    
      (integer_to_string (integer -> string)
        "Looks up the character that corresponds to the given integer (exact only!) in the ASCII table (if any).")
    
      (random (integer -> integer)
        "Generates a random natural number less than some given integer (exact only!).")
    
      (current_seconds (-> integer)
        "Evaluates the current time in seconds elapsed"
        " (since a platform-specific starting date).")
    
      (e real
         "Euler's number.")
      (pi real
          "The ratio of a circle's circumference to its diameter."))
   
    ("Booleans" 
      (is_boolean (any -> boolean)
        "Determines whether some value is a boolean.")
    
      (boolean_equal (boolean boolean -> boolean)
        "Determines whether two booleans are equal.")

      (is_false (any -> boolean)
        "Determines whether a value is false.")
    
      (not (boolean -> boolean)
        "Evaluates the negation of a boolean value."))

#|
   
    ("Symbols"
      (symbol? (any -> boolean)
        "Determines whether some value is a symbol.")
    
      (symbol=? (symbol symbol -> boolean)
        "Determines whether two symbols are equal.")

      (symbol->string (symbol -> string)
        "Converts a symbol to a string.")      )
|#
    ("Lists"
      (is_list (any -> boolean)
        "Determines whether some value is a constructed list.")
      (is_empty (any -> boolean)
        "Determines whether some value is the empty list.")
      (is_null (any -> boolean)
	"Determines whether some value is the empty list.")

      (cons (X (listof X) -> (listof X))
       "Constructs a list.")

      (null empty
	"The empty list.")

      (first ( (cons Y (listof X)) -> Y )
	"Selects the first item of a non-empty list.")
      (rest ((cons Y (listof X)) -> (listof X))
	"Selects the rest of a non-empty list.")
    
      (second ( (cons Z (cons Y (listof X))) -> Y )
	"Selects the second item of a non-empty list.")
      (third ( (cons W (cons Z (cons Y (listof X)))) -> Y )
	"Selects the third item of a non-empty list.")
      (fourth ( (listof Y)  -> Y ) ; domain: (cons V (cons W (cons Z (cons Y (listof X)))))
	"Selects the fourth item of a non-empty list.")
      (fifth ( (listof Y) -> Y ) ; domain: (cons U (cons V (cons W (cons Z (cons Y (listof X))))))
	"Selects the fifth item of a non-empty list.")
      (sixth ( (listof Y) -> Y ) ;  domain: (cons T (cons U (cons V (cons W (cons Z (cons Y (listof X)))))))
	"Selects the sixth item of a non-empty list.")
      (seventh ( (listof Y) -> Y ) ;  domain: (cons S (cons T (cons U (cons V (cons W (cons Z (cons Y (listof X))))))))
	"Selects the seventh item of a non-empty list.")
      (eighth ( (listof Y) -> Y ) ;  domain: (cons R (cons S (cons T (cons U (cons V (cons W (cons Z (cons Y (listof X)))))))))
	"Selects the eighth item of a non-empty list.")    
    
      (list_ref ((listof X) natural-number -> X )
	"Extracts the indexed item from the list.")
    
      ((internal-list list) (any ... -> (listof any)) "Constructs a list of its arguments.")
      
      (make_list (natural-number any -> (listof any)) 
        "Constructs a list of k (the first argument) copies of x (the second argument).")

      (append ((listof any) (listof any) (listof any) ... -> (listof any))
       "Creates a single list from several, by juxtaposition of the items.")
      (length ((listof any) -> number)
	"Evaluates the number of items on a list.")
      (member (any (listof any) -> boolean)
	"Determines whether some value is on the list")
      (remove (any (listof any) -> (listof any))
	"Constructs a list like the given one with the first occurrence of the given item removed"
	" (comparing values with equal?).")
      (reverse ((listof any) -> list)
	"Creates a reversed version of a list.")
      (assq (X (listof (cons X Y)) -> (union false (cons X Y)))
	"Determines whether some item is the first item of a pair"
	" in a list of pairs."))


    ("Posns"
      (posn (number number -> posn) "Constructs a posn.")
      (is_posn (anything -> boolean) "Determines if its input is a posn."))
#|

    ("Characters"
      (char? (any -> boolean)
	"Determines whether a value is a character.")
      (char=? (char char char ... -> boolean)
	"Determines whether two characters are equal.")
      (char<? (char char char ... -> boolean)
	"Determines whether a character precedes another.")
      (char>? (char char char ... -> boolean)
	"Determines whether a character succeeds another.")
      (char<=? (char char char ... -> boolean)
	"Determines whether a character precedes another"
	" (or is equal to it).")
      (char>=? (char char char ... -> boolean)
	"Determines whether a character succeeds another"
	" (or is equal to it).")
    
      (char-ci=? (char char char ... -> boolean)
	"Determines whether two characters are equal"
	" in a case-insensitive manner.")
      (char-ci<? (char char char ... -> boolean)
	"Determines whether a character precedes another"
	" in a case-insensitive manner.")
      (char-ci>? (char char char ... -> boolean)
	"Determines whether a character succeeds another"
	" in a case-insensitive manner.")
      (char-ci<=? (char char char ... -> boolean)
	"Determines whether a character precedes another"
	" (or is equal to it) in a case-insensitive manner.")
      (char-ci>=? (char char char ... -> boolean)
	"Determines whether a character succeeds another"
	" (or is equal to it) in a case-insensitive manner.")
    
      (char-numeric? (char -> boolean)
	"Determines whether a character represents a digit.")
      (char-alphabetic? (char -> boolean)
	"Determines whether a character represents"
	" an alphabetic character.")
      (char-whitespace? (char -> boolean)
	"Determines whether a character represents space.")
      (char-upper-case? (char -> boolean)
	"Determines whether a character is an"
	" upper-case character.")
      (char-lower-case? (char -> boolean)
	"Determines whether a character is a"
	" lower-case character.")
      (char-upcase (char -> char)
	"Determines the equivalent upper-case character.")
      (char-downcase (char -> char)
	"Determines the equivalent lower-case character.")
      (char->integer (char -> integer)
	"Lookups the number that corresponds to the"
	" given character in the ASCII table (if any)."))
|#
    
    ("Strings"
      (is_string (any -> boolean)
	"Determines whether a value is a string.")
      (string_length (string -> nat)
	"Determines the length of a string.")
      
      (string_ref (string nat -> string)
        "Extracts the ith 1-letter substring from the given one.")
      (replicate (nat string -> string)
        "Replicates the given string.")
      (explode (string -> (listof string))
        "Translates a string into a list of 1-letter strings.")
      (implode ((listof string) -> string)
        "Concatenates the list of 1-letter strings into one string.")
      (int_to_string (int -> string)
        "Converts an integer in [0,55295], or [57344,1114111] to a 1-letter string.")
      (string_is_numeric (string -> boolean)
        "Determines whether all 'letters' in the string are numeric.")
      (string_is_alphabetic (string -> boolean)
        "Determines whether all 'letters' in the string are alphabetic.")
      (string_is_whitespace (string -> boolean)
        "Determines whether all 'letters' in the string are white space.") 
      (string_is_upper_case (string -> boolean)
        "Determines whether all 'letters' in the string are upper case.")
      (string_is_lower_case (string -> boolean)
        "Determines whether all 'letters' in the string are lower case.")
 
      (substring (string nat nat -> string)
	"Extracts the substring starting at a 0-based index"
	" up to the second 0-based index (exclusive).")
      (string_append (string ... -> string)
	"Juxtaposes the characters of several strings.")
    
      (string_leq (string string string ... -> boolean)
	"Compares two strings character-wise.")
      (string_lt (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" precedes another.")
      (string_equal (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" succeeds another.")
      (string_gt (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" precedes another (or is equal to it).")
      (string_geq (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" succeeds another (or is equal to it).")
    
      (string_ci_leq (string string string ... -> boolean)
	"Compares two strings character-wise"
	" in a case-insensitive manner.")
      (string_ci_lt (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" precedes another in a case-insensitive manner.")
      (string_ci_equal (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" succeeds another in a case-insensitive manner.")
      (string_ci_gt (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" precedes another (or is equal to it)"
	" in a case-insensitive manner.")
      (string_ci_geq (string string string ... -> boolean)
	"Determines whether one string alphabetically"
	" succeeds another (or is equal to it)"
	" in a case-insensitive manner.")
    
      (string_to_number (string -> (union number false))
	"Converts a string into a number,"
	" produce false if impossible.")

      (format (string any ... -> string)
	"Formats a string, possibly embedding values."))
#|

    ("Images"
     (image? (any -> boolean)
       "Determines whether a value is an image.")
     (image=? (image image -> boolean)
       "Determines whether two images are equal."))
|#

    ("Misc"
      (identity (any -> any)
	"Returns the argument unchanged.")
      (error (any ... -> void) "signals an error, combining the given values into an error message.\n\nIf any of the values' printed representations is too long, it is truncated and ``...'' is put into the string. If the first value is a symbol, it is treated specially; it is suffixed with a colon and a space (the intention is that the symbol is the name of the function signalling the error).")
      (equal (any any -> boolean)
	"Determines whether two values are structurally equal.")
      (approx_equal (number number non-negative-real -> boolean)
	"Checks whether two numbers are within some amount (the third argument) of either other.")
      (eof eof
	"The end-of-file value.")
      (is_eof_object (any -> boolean)
	"Determines whether some value is the end-of-file value.")
      (exit ( -> void)
       "Exits the running program."))
))