Talk About Network



Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Programming > Forth > Re: Elegant cod...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 1 Topic 4014 of 4050
Post > Topic >>

Re: Elegant code Was: Re: what kind of non microconroller app are

by William James <w_a_x_man@[EMAIL PROTECTED] > Apr 24, 2008 at 02:32 AM

On Apr 21, 12:58 am, Jonah Thomas <jethom...@[EMAIL PROTECTED]
> wrote:
> Gerry <ge...@[EMAIL PROTECTED]
> wrote:
> > I've emailed you a copy. I'd appreciate it if you let me know how you
> > got on with it or if the email doesn't reach you
>
> It arrived intact. I've spent half an hour looking at it, I can follow
> in general what it's doing. It looks more complicated than I expected. I
> probably haven't noticed all the subtle problems that need to be solved.
>
> I want to ask anyone who's interested about a programming puzzle I ran
> into when I tried something similar.
>
> The idea is to have a routine GOOD-STRING that accepts a string ( ca len
> ) and an execution token that acts on the string and checks the first
> part of the string for some condition. Like, it couild test whether a
> character is an uppercase letter, or whether it's a digit, or
> alphanumeric, or whether two characters are ":=" or whatever.

Ruby:

--- code ---
p "abc"[ /^\d*/ ]
p "8abc"[ /^\d*/ ]
p "89abc"[ /^\d*/ ]

--- output ---
""
"8"
"89"

--- code ---
def good_string str
  str.size.times do |i|
    return str[0,i] if not yield str[i..-1]
  end
  str
end

p good_string( 'abc' ){|s| s =~ /^\d/ }
p good_string( '8abc' ){|s| s =~ /^\d/ }
p good_string( '89abc' ){|s| s =~ /^\d/ }

--- output ---
""
"8"
"89"

>                   The
> execution token should accept an address in the string, and it returns a
> flag.
>
> XT ( ca -- flag )
>
> The routine does ( ca len xt -- ca len' ) . It returns as much of the
> string as meets the condition the execution token tests for.
>
> So I'd wind up with:
>
> : STRING-CHECKER ( S: xt "name" -- )
> ( child: ca len -- ca len' )
>    CREATE ,
>    DOES> @[EMAIL PROTECTED]
 GOOD-STRING ;
>
> to make a collection of named routines to check strings in various ways.
>
> My first attempt at GOOD-STRING was like this:
>
> : GOOD-STRING1 ( S: ca len xt -- ca len' )
>    >R
>    2DUP BEGIN
>      DUP 0 > WHILE
>        OVER R@[EMAIL PROTECTED]
 EXECUTE WHILE
>          1 /STRING
>      REPEAT
>    THEN
>    NIP - RDROP ;
>
> This works adequately but it's clumsy. A complicated loop and a return
> stack item. No way to simplify it that matters, not without getting rid
> of either the complex loop or the >R or both. Using locals would handle
> it easily but I didn't want to do that. I thought there ought to be a
> good way to do this without locals. I only care about 3 items, surely I
> can handle 3 stack items.
>
> So I tried to get rid of the loop with recursion. I had just the looping
> part recurse.
>
> : CHECK-STRING2 ( ca len xt -- ca' len' xt )
>    OVER 0 > IF
>      >R OVER R@[EMAIL PROTECTED]
 EXECUTE IF
>        1 /STRING R> RECURSE
>      ELSE
>        R>
>      THEN
>    THEN ;
>
> This is not great. My first recursive approach was even worse. I tried
> to get rid of the xt, but then I needed extra branches to get rid of it
> consistently. Easier to DROP it once when the routine is done. I figure
> branches are a little better than loops and there's only one RECURSE
> isntead of two WHILEs. But it isn't simple and there's no obvious way to
> factor it.
>
> I could get rid of the return stack ops by using DEFER .
>
> DEFER CHECKER
> : CHECK-STRING3 ( ca len -- ca' len' )
>    DUP 0 > IF
>      OVER CHECKER IF
>        1 /STRING RECURSE
>      THEN
>    THEN ;
>
> The DOES> child can simply put the xt into CHECKER and it works. Simple.
> But not easily re-entrant. I will want to be checking a string and in
> the middle I'll need to start checking for something else, and then
> continue where I left off. To do that I have to save the old value of
> CHECKER and there's no standard way to get that. I'd have to save the
> old value on a stack. The complication pops up there.
>
> So I did without the deferred variable.
>
> : CHECK-STRING4 ( xt ca len -- xt ca' len' )
>    DUP 0 > IF
>      OVER 2OVER DROP EXECUTE IF
>        1 /STRING RECURSE
>      THEN
>    THEN ;
>
> Changing the stack order helped some. The return stack mess is gone, and
> the side branches. The only troublesome bit is a little spot of stack
> noise. Would 3PICK look better than 2OVER DROP ?
>
> I can make it look nicer.
>
> : CHECK-STRING5 ( xt ca len -- xt ca' len' )
>    3DUP 0 > IF
>      SWAP EXECUTE IF 1 /STRING RECURSE THEN
>    THEN ;
>
> 3DUP is not really simpler than 3PICK . It's easier for me to see what's
> going on, but the obvious way to implement 3DUP in high-level standard
> Forth is : 3DUP 2PICK 2PICK 2PICK ;
>
> Only 3 stack items. Why is it so hard? Because with ( a b c ) the things
> we need to do require copies
>
> len
> ca xt
> ca len      original, not copy
> xt ca len   original
>
> There's no way to get all four patterns without some stack juggling. (Or
> locals.)
>
> When is this sort of perfectionism justified? I got something that
> worked in 3 minutes. After a series of false starts I got something that
> approched elegance. It still has a RECURSE so it wouldn't be as easy to
> debug at the keyboard as something that didn't have recursion or loops.
> Luckily it passed my tests the first try.
>
> : GOOD-STRING2 { ca len xt }
>    ca len BEGIN
>      DUP 0 > WHILE
>        OVER xt EXECUTE WHILE
>          1 /STRING
>      REPEAT
>    THEN
>    NIP ca len ROT - ;
>
> A few locals are enough to get past some of the worst problems. And if a
> few locals are good, maybe more locals are better. With 2 more locals
> and liberal use of TO I can eliminate every stack word.
>
> : GOOD-STRING2 0 0 { ca len xt ca' len' }
>    ca TO ca' len TO len' BEGIN
>      len' 0 > WHILE
>        ca' xt EXECUTE WHILE
>          ca' len' 1 /STRING TO len' TO ca'
>      REPEAT
>    THEN
>    ca len len' - ;
>
> Better? Not only do you eliminate the stack words, the stack comments
> are part of the code.
>
> When is it worthwhile to make the code simple? I have to figure the
> ideal approach is to do it simply the first time. If you write elegant
> code quickly, so the first version is easy to understand and easy to
> test and easy to document etc, then you don't have to think about how
> much time to spend improving it.




 1 Posts in Topic:
Re: Elegant code Was: Re: what kind of non microconroller app ar
William James <w_a_x_m  2008-04-24 02:32:29 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Sun May 11 20:19:19 CDT 2008.