Benutzer-Werkzeuge

Webseiten-Werkzeuge


projects:forth_style
  PORTED FROM UseNet =>
              ------

 From: ir230@sdcc6.ucsd.edu (john wavrik)
 Newsgroups: comp.lang.forth
 Subject: Style
 Message-ID: <12149@sdcc6.ucsd.edu>
 Date: 3 Aug 90 03:49:06 GMT
 Organization: University of California, San Diego

 Wil Baden has started a discussion of Forth style. I dug out the 
 following example which I once used in a Forth course. The task is 
 simple enough that it can be easily understood -- and difficult enough 
 so that style matters. It was chosen so that the issue would be coding 
 (rather than improvement in algorithm, knowledge of math, etc.)

 TASK:  Write a program in which the computer uses binary search to 
        guess a user's "secret" number.  The user thinks of a secret 
        number, an integer from 1 to 100. The computer makes a guess 
        to which the user must respond by typing LOW, HIGH or RIGHT. 
        This is repeated until the computer guesses the number.

 I don't remember what version of Forth we were using when this was 
 written -- but it shouldn't matter unless you plan to actually run it. 

 We used the following words from a string package (all strings are 
 counted with a 1-byte count and are represented by their address):

 $VARIABLE    ( n -- )  defining word for string variables.
              <n> $VARIABLE X  allocates storage for a counted string 
              of length n. When X executes the address of the string is 
              put on the stack.

 $"           ( -- $addr ) the following text up to a delimiting " is 
              stored as a counted string. The address of the string is 
              put on the stack.

 IN$          ( -- $addr ) accept a string from the keyboard until <cr>.
              The input is stored as a counted string whose address is 
              put on the stack.

 $COMPARE     ( $1 $2 -- -1|0|1 ) compares counted strings. Returns -1 
              if $1 comes before $2 in lexicographic order, 1 if it 
              comes after, and 0 if the strings are equal.

 $!           ( $ addr -- ) copy counted string at address $ to addr.
              Typical usage  $" HELLO" X $!  where X is a string 
              variable.

 Here is a solution to the problem which shows why some people think 
 Forth is a write-only language: 

 ( GUESSING GAME PROGRAM                                 1  )
 10 $VARIABLE A
 :  GO  BEGIN 0 101 BEGIN  2DUP + 2/  DUP  CR ." I GUESS "  . CR BEGIN 
 ." IS THAT HIGH, LOW, OR RIGHT " IN$ A $! A $" HIGH" $COMPARE  0=  IF 
 SWAP DROP 0 1 ELSE A $" LOW" $COMPARE 0= IF ROT DROP  SWAP  0 1 ELSE A 
 $" RIGHT" $COMPARE 0= IF CR ." I  GOT IT!!" DROP DROP DROP BEGIN CR ." 
 PLAY AGAIN (Y OR N)" KEY DUP 78 = IF DROP  1  1 1 1 ELSE 89 = IF 0 1 1 
 1 ELSE 0 THEN  THEN  UNTIL ELSE CR 0 THEN THEN THEN UNTIL UNTIL UNTIL ; 

 ( Why spend hundreds of dollars for a program to obfuscate your source 
 code?  You can do it yourself for less in Forth! )

 Actually, something like this can be done in any language. I did it by 
 removing the indentation from the following program. The following is 
 bad style also. It is a transcription to Forth of a program which the 
 student originally wrote in Pascal (this stuff comes from several 
 years back when Pascal was the "in" language). I don't think this is 
 what Wirth had in mind when he invented Pascal -- but it seems typical 
 of the way many people write Pascal and 'C': 

 ( GUESSING GAME PROGRAM                                 2A )
 10 $VARIABLE ANSWER
 : GAME   BEGIN 0 101
           BEGIN  2DUP + 2/  DUP
                  CR ." I GUESS " .  CR
                BEGIN  ." IS THAT HIGH, LOW, OR RIGHT "
                       IN$  ANSWER $!
                       ANSWER $" HIGH" $COMPARE 0=
                       IF   SWAP DROP 0 1
                       ELSE ANSWER $" LOW" $COMPARE 0=
                         IF   ROT DROP SWAP 0 1
                         ELSE  ANSWER $" RIGHT" $COMPARE 0=
                             IF CR ." I GOT IT!!"  DROP DROP
                                DROP
                                BEGIN CR ." PLAY AGAIN (Y OR N)"
                                      KEY DUP 78 =    -->

 ( GUESSING GAME PROGRAM                                 2B )
                                      IF   DROP 1 1 1 1
                                      ELSE  89 =
                                         IF  0 1 1 1
                                         ELSE 0
                                         THEN
                                      THEN
                                UNTIL
                            ELSE  CR 0
                            THEN
                         THEN
                       THEN
                UNTIL
           UNTIL
         UNTIL ;

 [I notice in reproducing it that the programmer forgot to deal with the 
 case in which the user types in something other than HIGH, LOW or 
 RIGHT.] 

 The guessing game program is logically more complex than it might 
 first appear. You might want to see what you can do with it before 
 reading the code below. 

 =======================================================================


 ( GUESSING GAME PROGRAM                                 3A )
 VARIABLE LL   VARIABLE HH   ( low and high for current range )
 VARIABLE GG                 ( current guess )

 : GUESS  CR  ." I guess "
         LL  @  HH  @  + 2/     ( guess  midpoint  of  range  )
         DUP    GG   !    .     ( and store guess  )
         ." is that LOW, HIGH, or RIGHT" ;

 : START  0 LL !  101 HH !  GUESS  ;

 :  HIGH    GG @ HH !  GUESS   ;  ( take lower half of  range )
 :  LOW     GG @ LL !  GUESS   ;  ( take upper half of  range )
 :  RIGHT   CR ." Wow, I got it!!"  ;

 In this version, the complexity of nested control structures has been 
 elminated by factoring. The Forth interpreter has been made part of 
 the game (LOW and HIGH are not strings decoded by the program -- but 
 are now Forth words). The low and high bounds and the guess were put 
 in variables rather than left on the stack: if the user puts in a bad 
 response, the Forth interpreter will trap the error -- but also will 
 clear the stack. Putting the numbers in variables allows the game to 
 continue after an error. 

 While I won't claim that this version is the ultimate, I do feel that 
 someone can read the code and understand what is going on. I do not 
 feel this is true of either of the earlier versions.

 ======================

 To Wil Baden and others who may be interested in this:

     I recently was asked by someone why I was using Forth to do work 
 in Computer Algebra rather than Scheme or a Computer Algebra system 
 (like MACSYMA, Maple, Mathematica, etc). I answered that, among other 
 things, I feel that it is easier to write clear code in Forth. To 
 prove my point, I found a computer algebra project for which I have 
 code written "by the masters" (by Ableson and Sussman^2 in Scheme, and 
 by David Stoutemyer in MuSIMP -- the implementation language for the 
 MuMATH computer algebra system he created). In both cases the authors 
 were explaining to students how to do the project -- so I must assume 
 they tried to make their work a model of clarity. I think that the 
 improvement of the Forth version over the other is substantial. The 
 difference would be visible to anyone who knows the three languages 
 and a bit about symbol manipulation. [The comparison is too long to 
 post, but I would be willing to email it -- and I would welcome 
 detailed comments by others who are interested in using Forth in 
 mathematics] 

    I believe that, potentially, Forth can be quite clear -- just as I 
 think, potentially, that Forth can be quite portable. In both cases 
 the barriers are not in limitations of the language. 

                                                   John J Wavrik 
              jjwavrik@ucsd.edu                    Dept of Math  C-012 
                                                   Univ of Calif - San Diego 
                                                   La Jolla, CA  92093 
----------

projects/forth_style.txt · Zuletzt geändert: 2013-06-06 21:27 von 127.0.0.1