Arc Forumnew | comments | leaders | submitlogin
Confused by endmatch
2 points by conanite 3090 days ago | 3 comments
strings.arc defines endmatch as

  (mac endmatch (pat string)
    (w/uniq (gstring glen)
      `(withs (,gstring ,string ,glen (len ,gstring))
         (unless (> ,(len pat) (len ,gstring))
           (and ,@(let acc nil
                    (forlen i pat
                      (push `(is ,(pat (- (len pat) 1 i)) 
                                 (,gstring (- ,glen 1 ,i)))
                    (rev acc)))))))
yet, this seems to do the expected job:

  (def match-end (pat str)
    (is (cut str (-:len pat)) pat))
What's more, this doesn't work

  (endmatch (get-a-string-from-somewhere) str)
, because endmatch is expecting a literal string for its "pat" argument - "pat" is not unquoted anywhere inside endmatch.

Is endmatch more efficient? Or what is the advantage of writing it this way?

2 points by CatDancer 3090 days ago | link

You can see the expansion of endmatch for a particular pat argument using macex1, which shows you the expansion of a macro:

  arc> (ppr:macex1 '(endmatch "foo" s))
  (withs (gs1453 s gs1454 (len gs1453))
         (unless (> 3 (len gs1453))
           (and (is #\o (gs1453 (- gs1454 1 0)))
                (is #\o (gs1453 (- gs1454 1 1)))
                (is #\f (gs1453 (- gs1454 1 2))))))
so you can see why pat has to be a literal string with this implementation.

As to whether unrolling the match in this way will actually be more efficient... we'd need to run some timing tests to find out ^_^

By the way, it looks like your implementation of match-end doesn't work in arc2, I guess it doesn't have the negative index feature to cut from the end of a string.


1 point by conanite 3088 days ago | link

timing tests ... ok, endmatch totally wins. Especially for a mismatch in which case endmatch returns early, but match-end shows no gain. These tests were run on anarki arc:

  average time im ms over 100000 runs of [_ ".jpg" "hello.jpg"]
  endmatch     0.029
  match-end    0.064

  average time im ms over 100000 runs of [_ ".jpg" "hello.png"]
  endmatch     0.016
  match-end    0.062
So it seems performance is a likely explanation for the way endmatch is implemented.

(interestingly, for comparison, on rainbow the time for endmatch is roughly similar (0.028,0.019) but for match-end is disastrous (0.11,0.11). I'll need to figure out why.)

You're right about my match-end not working on arc2 - I mostly use anarki as it has a bunch of convenient changes including negative offsets for cut.


3 points by CatDancer 3088 days ago | link

match-end is disastrous

Though keep in mind that effort making a particular function run faster is only useful if a significant percentage of a program's execution time is spent in that function. For example, even if your match-end runs four times slower than endmatch in rainbow, if a program spends only 0.01% of its time matching the end of strings, then making match-end run faster won't help the program run any faster.

Certainly as an optimization arc2's implementation of endmatch would appear to be premature one, considering that endmatch isn't even used in the arc2 and HN source code, much less identified (as far as I know :) as a hot point slowing down the execution of someone's program. And while I do personally find it to be a fun piece of code (demonstrating how loop unrolling can be done using macros), your implementation is a clear winner in clarity and succinctness. :-)