In my years in Smalltalk (while wishing I was doing Prolog) a lasting issue was our continued vulnerability to array bounds errors.
In Curl, {value
{{String "full string too short"}.substr 8, 9}} succeeds (evaluation can proceed forward) whereas
{value {{String "full string too short"}.substr 8, 42}} raises an Array bounds exception.
However in Curl
{value
{for str:String in {{String "www.curl.com"}.split split-chars = {CharClass ","}} do
|| we only have a comma char in our CharClass init string
{text str}
}
}
does not 'fail' even though the string cannot "succeed" in splitting into parts.
In a language for which a String is just an array of char, (i.e. a byte) this is understandable.
In Icon, if I had some strings and the one I look at is not the right length, I step back and look at the next item
If none is the right length ( excuse the Pythonic pun) and if I can step back from that expression, then I step back.
This backtracking is not unlimited: it is based on the success or failure of evaluated expressions.
A previous success where a variable was bound will stop the backtracking ( unlike the prolog strategy of unification )
This {eval expr} strategy is able to replace many "statement-like" switch/case and if/then/elseif/else with some very simple expressions.
In today's Curl, I know of nothing comparable to Python's slice, which does not raise an exception for "test"(1:13) (pretend those are square brackets)
In Curl,
{ {String "test"}.find 'Z', starting-index = 42 } raises an ArrayBoundsException
We have {try } but do not have, say, an
{attempt } on which the expressions within the attempt expression do not raise exceptions.
Suppose you could have a container of strings and you could 'look' at each, as Turing might have said, and attempt to see the 42nd character.
On day n1, the list has only short strings ( where short means less than 42 ) We capture this test expression with, say, a tilde-operator
( item.zero-based-length
~< Universe . answerLength )
or with some other syntactic sugar to indicate that the expression may succeed or may fail ( does not resolve to a boolean value but to a choice: proceed or try to backtrack). In a future Curl we might have this way of evaluating an expression:
{*attempt* {list item }
{ does item(Universe . answerLength)
|| ... "does" might be better "satisfies" ?
} } || note that this is not a WHILE or an UNTIL expression nor is it just a sugared {for do {if
|| because if this attempt is a possible step of another attempted goal, we may be back !
|| ( as if we handed them a proc-type of iterator whose NEXT returns a MORE until it returns a EMPTY )
In the classic Icon examples you would recognize Python generators with yield or our own Curl .to-Iterator
The prospect that I see is for much cleaner Curl code with fewer {for do} and far fewer {if then elseif }
Likely someone at Curl can say off-hand how much of the success | fail goal behavior could be implemented using a macro named {attempt } without introducing a type which is not boolean, say Outcome, with two values, succeed and fail.
My naive approach is to say that for any list of items for which to attempt the eval of an expr there could be an underlying list of uninitialized outcome values that resolve to true or false assignments as the evaluation of an expression succeeds or fails and the boolean evaluation of that 'list' corresponds to the result of a goal-attempt AND or OR for the list of items and the simulated generator. Because that list is indexed, you can backtrack from a failure subsequent to some indexed success s >= n > 0 to a previous indexed success at s < n > 0. Each of those could point back to another such list. Having no such underlying list for a given index s would amount to prior expressions being 'bound' ( limited backtracking ). Think of this as starting as (null, null, null) and progressing to (fail,success,success) to (fail, success,fail) to (fail,bound,fail) which would read that we backtracked into the second item and there found a final success. Or we might have ended in failure at (fail, fail,fail) or even had very early success terminating evaluation with (bound, null, null) such that we never re-enter to try evaluation of item(1) and item(2) Naturally on this approach an item cannot be bound until any underlying list has a bound item and does not fail until an underlying list has items all of which failed or we fail with an underlying list where we were branched off the last success, which thereby fails to bind and so back down the chain to a success where a bound assignment occurs or we fail. And there are interesting options to proceed breadth first or depth first { atttempt strategy = shallow, list, item
And so to my second cup of Saturday morning coffee. Note: Backtracking may be more often thought of as PROLOG. For the various efforts to meld prolog and Smalltalk see my page at aboutus.org
or to see prolog in another multi-paradigm functional language see
OZ, the language (for which there is a book which CURL might envy.) For typed-prolog, see
http://www.pdc.dk/ or the Mercury project (where I believe someone now has Mercury running on top of Erlang - but where there is no UNICODE) PDC focussed on having an IDE and at the other end of the gamut, Mercury still has no IDE. Prolog evolved to PROLGIA clp and continues to evolve, significantly as
XSB at
xsb.sourceforge.net And for forward rather backward, see production systems, such as JESS, the Java interface to a PS. BTW, POPLOG remains active at U. Birmingham on the Greenwich side of the drink. For Windows, Strawberry Prolog is active in Sofia. For O-O Horn-clause backtracking+unification, the most interesting project to my mind is that at
www.logtalk.org For a real curiosity there is EZY Prolog using dialogs ( analogies with Curl spring to mind - ah, there's the coffee now ... )
PS For Windows, if you attempt
UNICON, install to C and save your icn files to UNICON\bin even after you set that in the PATH IFF you have problems.