On Jun 6, 2007, at 5:21 AM, Andreas Launila wrote: > James Edward Gray II wrote: >> On Jun 5, 2007, at 2:43 PM, Andreas Launila wrote: >> >>> == Issues == >>> >>> === Describing (linear) constraints === >> >>> A problem with the above is that people might look at it and >>> instinctively think that it's something that does not have a side >>> effect. Therefore prepending some sort of method might convey that >>> intention better. For instance we could allow people to write the >>> following. >>> >>> constrain x + y == z >> >> RSpec works a lot like this. It has you define expectations with >> syntax >> like: >> >> some_obj.should equal(whatever) >> some_obj.should_not equal(whatever) >> >>> Fitting words other than "constrain" might be "assert", "post" and >>> "add". >> >> I like the word "constrain." If you go the RSpec route though, >> you will >> probably also want a negative form and I don't know what that >> would be. >> > > That would be a nice solution. The best word I can think of for > "constrain" is "constrain_negation", which is probably far from > perfect. > > constrain_negation x + y == z Yuck. And I mean that in the nicest possible way. ;) > Another variation would be to use a combination of constrain and > RSpec's > should/should_not. > > constrain (x + y).must == z > constrain (x + y).must_not == z That's not too bad. I think my biggest complaint there is that it makes the flow of the line a little hard to follow. Perhaps must/ must_not could replace constrain altogether though: must x + y == z must_not x + y == z That doesn't read too well though, does it? > As an example there's a domain > constraint which basically says that x must be in a given range. > Negating the constraint is possible and might be written as follows. > > constrain x.in(1..17) > constrain x.not_in(1..17) This seems like a very viable solution to me. If it's possible to just negate all of the tests, that should work: equal/not_equal in/not_in includes/does_not_include >>> === Overall syntax === >>> >>> Every model has at least three parts: >>> * Declaration of variables (in the example that would be "squares >>> = ...") >>> * Definition of constraints (all the lines from >>> "all_distinct ..." down >>> to "squares.diagonal..." in the example). >>> * Selection of branching strategy (the line starting with >>> "branch_on" in >>> the example) >>> >>> Maybe that could be used to produce some other overall syntax? E.g. >>> something other than throwing it all into a constructor. >> >> Reading this definitely made me wonder over a DSL. That's pretty >> much >> what you have with the class system though. If constrain() >> becomes the >> constraint definer and branch_on() represents the branching strategy, >> the only thing you haven't really wrapped is the variable >> declaration. >> >> I don't know what that would look like, but maybe something like: >> >> variable :some_name, :int, accepted_range_of_values >> >> Then I guess you could later refer to them by name. Of course, >> that's >> just not as convenient when it comes to accessing them. Iterating >> over >> rows and columns shows this well. > > I don't understand the part about not being as convenient to > access. I'm > assuming that one could define matrices just as well as single > variables > with such a syntax, which would basically give the same level of > convenience. An example to see if I understood you correctly (possibly > with some keys for the parameters beyond the name and type): > > class MagicSquare < Gecode::Model > def initialize(n) > variable :squares, :int_matrix, n, n, 1..(n**2) > squares.row(0) > ... > end > end I think this makes it more complicated to support custom data structures. What if I want a MyUniqueDataStructure full of IntVars, for example? Beyond that, it doesn't seem in anyway superior to: class MagicSquare < Gecode::Model def initialize(n) @squares = ... end attr_reader :squares end I think it's probably best not to override core Rubyisms if we can't significantly add to them. James Edward Gray II