One really rapidly hits an enormous amount of questions just by doing such exercises, which somehow always take about 20h more than expected. I will have to ask later.
Definitely seems to work, all units tests passed (UPDATED after bug fix)
- Test cases:
between_with_step.pl(.plt files are not shown correctly by the github syntax colorating system; it thinks .plt is gnuplot. Who codes like that?)
- Getting it to be semi-deterministic.
- The advantage of tagged integers (i.e. use
Xis a positive integer to take advantage of pattern matching) becomes evident.
- Then rearranging arguments to get the most out of matching.
- The compiler should help in flagging unnecessary cuts (I just left them in, deal with it Mr Compiler).
- …and that would actually help in deciding whether clause indexing is at it should be (maybe?)
- Some unit testing features could be added (testing semi/determinism & a size-limited “all”)
- Standard exception terms as defined by ISO are sadly inflexible and non-regular (varying between compound terms of arity 3,2,1 and an atom?). What happened here?
- must_be/2 needs a third arg to indicate which variable actually failed. But there is nowhere in the ISO exception term where you can actually put that third arg. Suboptimal.
- Passing an options list to a predicate to cover a few cases that might be of interest to the programmer (e.g. throw vs. fail on empty sequence) feels like an excellent and simple idea.
- Binding arguments that no caller needs just for documentation/debugging purposes doesn’t seem like a bad idea either as long as one does not need to change the program structure just for those (they can “tag along”).
- I haven’t done this in this code, but sometimes one wants to add an argument just to take up the information destroyed by the predicate (e.g. list items removed by the predicate) instead of throwing the information into the heat sink. Then the predicate can run properly backwards too (“reversible computing” in Prolog, right?)