subset
:: pusher ( quot -- quot accum )
V{ } clone [ [ push-if ] 2curry ] keep ; inline
: subset ( seq quot -- subseq )
over >r pusher >r each r> r> like ; inline
The idea of having a
pusher
word was originally suggested by Eduardo Cavazos. This word takes a predicate quotation and yields two values, the first being a quotation taking an object as input, and the second being a vector. If you call the quotation with an object for which the predicate yields true, the object is pushed on the vector. The generated quotation "closes over" the vector. Now the only thing subset
has to do is pass the pusher quotation to each
, and hide the pusher vector on the retain stack until after the iteration is done. When iteration has completed, the pusher vector contains all elements which passed the predicate.I think there is a very interesting idiom here, and it is worth exploring this idea more.
Also, note that while from the outside,
subset
is referentially transparent, it uses mutable state internally. While it may be possible to write something just as simple without mutation, I think in many cases, being able to mutate considerably simplifies code; certain algorithms are just more naturally expressed with mutation, at least in a stack language, and integrating abstractions such as monads or uniqueness types into a stack language is still an open research problem (but Christopher Diggins is working on it...) There is something to be said for allowing different programming styles in a language, instead of forcing a single style on the programmer (as in Haskell and other purely functional languages, or even Smalltalk's "everything-is-message-passing-OOP".)
No comments:
Post a Comment