%%HP: T(3)A(R)F(.);
\<<
  @ PTYPE expects a string on the top of the stack
  @ indicating the types of values to expect on the rest
  @ of the stack. So check that:

  @ 1) there is at least one item
  IF DEPTH 2. < THEN #201h DOERR END  @ Too few args

  @ 2) the first item is a string
  IF DUP TYPE 2. \=/ THEN DROP #202h DOERR END @ Bad arg type

  @ 3) there are at least as many values on the
  @ stack as there are characters in the string.
  IF DEPTH OVER SIZE > THEN #201h DOERR END

  @ Keep the stack as it is and simply write the test
  @ results over the top of the test string.
  @ So, stack usage at the start of the main loop is:
  @ 
  @ n: param n-1
  @    ...
  @ 3: param 2
  @ 2: param 1
  @ 1: string specifying the parameter types
  
  @ Go through the string and check each type against
  @ the value on the stack.
  @ (Start from char 2 as the first is special)
  2. OVER SIZE FOR a

    @ Get the a'th parameter
    a PICK

    @ Get its type
    DUP TYPE

    @ Get the a'th code character
    PICK3 a a SUB

    @ And save these three as local variables
    \-> p t c \<<

      @ If the parameter is tagged then remove the tag
      @ (unless the test is explicitly for a tagged value)
      IF t 12. ==  c "t" \=/  AND
      THEN
        p DTAG 'p' STO
        p TYPE 't' STO
      END

      @ If the parameter is a variable then retrieve its 
      @ contents
      @ (unless the test is explicitly for a variable)
      IF t 6. ==  t 7. ==  OR
         c "v" \=/  AND 
      THEN
        p VTYPE 't' STO
        p RCL 'p' STO

        @ Do the tags test again (because a local var
        @ can hold a tagged value even though a
        @ global can't)
        IF t 12. ==  c "t" \=/  AND
        THEN
          p DTAG 'p' STO
          p TYPE 't' STO
        END

      END

      @ Finally, we get to the 'actual' tests. Each
      @ case statement test checks one of the character
      @ code types and leaves a true/false value on
      @ the stack.
      @ (The case order affects the speed of execution so
      @ they are ordered with the most common first)
      CASE
        c "n" == THEN    @ Number
          t 0. ==  t 28. ==  OR
        END

        c "f" == THEN    @ Formula/Function
          t 9. ==
        END

        c "a" == THEN    @ Array
          t 3. ==  t 4. ==  t 29. ==  OR OR
        END

        c "l" == THEN    @ List
          t 5. ==
        END

        c "s" == THEN    @ String
          t 2. ==
        END

        c "c" == THEN    @ Complex number
          t 1. ==
        END

        c "b" == THEN    @ Binary
          t 10. ==
        END

        c "p" == THEN    @ Program
          t 8. ==
        END

        c "2" == THEN    @ 2 element vector
          IF t 3. ==  t 29. ==  OR
          THEN
            p SIZE {2.} ==
          ELSE
            0.
          END
          t 1. == OR
        END

        c "3" == THEN    @ 3 element vector
          IF t 3. ==  t 29. ==  OR
          THEN
            p SIZE {3.} ==
          ELSE
            0.
          END
        END

        c "u" == THEN    @ Number with units
          t 13. ==
        END

        c "t" == THEN    @ Tagged object
          t 12. ==
        END

        c "v" == THEN    @  Variable
          t 6. ==  t 7. ==  OR
        END

        c "g" == THEN    @ Graphic
          t 11. ==
        END

        c "-" == THEN    @ Any type allowed
          1.
        END

        @ Default -> unknown/unexpected so error
        0.
      END

      @ Update the result string with the outcome
      IF THEN "." ELSE "x" END
      a SWAP REPL

    \>>
  NEXT

  @ Report final error status - "x" marks the spot!
  DUP "x" POS
  IF OVER HEAD "T" ==
  THEN
    @ Turn POS value into 0. or 1.
    NOT NOT

    @ Start the result string with "R"
    SWAP 1. "R" REPL SWAP
  ELSE
    @ Report error
    NIP IF THEN #202h DOERR END
  END
\>>
