"constraints placed on the nodes to enforce rules about which nodes can connect to which nodes" I couldn't agree more but I guess I don't see how to express certain constraints in this particular framework. say you have a function F : (forall a. a -> a) -> Int (where ':' means "of type") and a function G : (Int -> Int) -> Int. As well say there are two expressions, X : forall a. a -> a and Y : Int -> Int Assume two trees (call them A and B) have forms (F X) and (G Y) respectively and A and B are selected for crossover. The nodes for X and Y are chosen to be swapped. sense X's type unifies with Int -> Int and Y's type unifies with forall a. a -> a the crossover is allowed. That said it should not be allowed that Y be passed to F. The expression (F Y) is ill-typed. On the other hand the expression (G X) is fine and perfectly valid. How then can I express the constraint that Y can not be passed to F but that X can be passed to G? Sense compatibleWith is commutative and the constraint I specify is not it would appear that this cannot be expressed using compatibleWith; something else must be needed. I like functional programming and type systems, hence the choice of types. I can reformulate this in terms of Java or some other language however. For instance say there is an interface class "Shape" and another class "Square". say F : Square -> Int, G : Shape -> Int, X has type Square, and Y has type Shape. The same issue arises F Y is ill-typed but G X is not. The issue seems to arise anytime a return type is allowed to be more than atomic, that is there is a notion of more than 1 type "belonging" to the return type weather it be parametric polymorphism, set types, or subclass polymorphism. Am I missing something and/or is there a way to express the desired constraint? On Jan 11, 2014 10:21 AM, "Sean Luke" <[log in to unmask]> wrote: > Types are not data passed between nodes. They are merely constraints > placed on the nodes to enforce rules about which nodes can connect to which > nodes. > > Now, it's true that types often are correlated with the kinds of data that > nodes send to each other, but that's hardly a requirement. For example, > we're using types right now simply to force certain kinds of nodes to > appear in the top area of a tree but not down near the leaf nodes. > > The most common situation you'll find is argument types which are set > types, and return types which are atomic types. For example, you might > have a node which returns int plugged into an argument which can accept int > or double. You've seen that before in real programming languages I'm sure: > the + operator in most programming languages can take floats, ints, > doubles, longs, bytes, indeed in some cases strings. > > All you have to do is handle multiple kinds of data in your GPData object. > The typing mechanism merely guarantees that when a node receives a GPData > object, what you receive has been constrained in a way that you had > specified. > > Sean > > On Jan 11, 2014, at 10:52 AM, Jake Ehrlich wrote: > > > OK that explains more. Thanks for the clarification > > > > As to the example, yes you understood. I am still confused however on > how something of type {s, i} can be passed in to something expecting an > integer. What if that something returned a string? > > > > On Jan 11, 2014 8:59 AM, "Sean Luke" <[log in to unmask]> wrote: > > On Jan 11, 2014, at 2:00 AM, Jake Ehrlich wrote: > > > > > In the documentation for ec.gp.koza.CrossoverPipeline it says "Then a > random > > > node is chosen in each tree such that the two nodes have the same > return > > > type". Does "same return type" in that quote mean that the types "fit" > by > > > GType's compatibleWith method? > > > > The documentation is misleading. The correct form is: > > > > Two nodes M and N are chosen. Let R(N) and R(M) be the return types of > > M and N respective. Let A(N) and A(M) be the types of the argument slots > > which N and M respectively fill in their parents. Then M and N are only > > valid if R(N) is type compatible with A(M) and R(M) is type compatible > > with A(N). > > > > > First off as I understand it GType.compatibleWith is assumed to be > > > commutative (that is t1.compatibleWith(init, t2) is true if and only if > > > t2.compatibleWith(init, t1) is true). Is this correct or is it just > one way? > > > > compatibleWith is commutative. > > > > > > > Say you have a node X of type {string, int} (a set type) and another > node Y of > > > type int (an atomic type). X and Y are being passed in as parameters > of type > > > {string, int} and int respeticvlly. These return types are > "compatible" ("fit") by > > > the definition of compatibleWith for GPAtomicType and GPSetType yet you > > > shouldn't be allowed to swap them sense the parameter type of X's > parent > > > can't handle a string, only an int. > > > > Let me make sure I understand what you're saying. Node X is of return > type {s,i} and it's attached to an argument slot of type {s,i}. And node Y > is of return type i and is attached to an argument slot of type i. If you > swapped them, then node X would now be in the argument slot i (which it is > type-compatible with) and node Y would now be in argument slot {s,i} (which > it is also type-compatible with) so everything would be fine. > > > > Sean >