On Mon, Oct 5, 2009 at 6:37 PM, Waldek Hebisch wrote: > Bill Page wrote: >> I hope you do not mind continuation of this discussion. > > I should be really doing something else, but could not > resist so I wrote quick answer. >
Thanks. :-) i do appreciate that this discussion might seem too "philosophical" and you might have the feeling that it would be better to spend time on something else. Still I would prefer it if we could reach some kind of agreement or at least understand why we don't agree. I will certainly try, where possible, to backup this discussion with actual code. > ... > Hence my conclusion is that it is better to leave 'Void' for > compiler, because once you invent something which is > one step beyond trivial it will be too hard for compiler. > And it seems foolish to spend effort implementing trivialities. > I agree that ideally 'Void' and 'None' should be essentially trivial and that they should be known and handled by the compiler in the same way that 'Record' and 'Union' are handled now - although of course the treatment of all of these could be better than it is now. It may seem foolish to spend time implementing trivialities but it if we do not get the trivial things correct I think it almost always makes implementing non-trivial things in a consistent and general manner that much harder. >> ... >> The idea that Void should be automatically involved in the resolution >> of types in expressions like >> >> if n=0 then x::Integer else y::Float >> >> does not make sense to me. > > So, what type the above should have? Do you want type error? > A good type for if n=0 then x::Integer else y::Float might be 'Union(Integer,Float)'. Such a construction is "free" in the sense that 'Union' implements a corresponding 'case'. >> ... >> No I am not concerned about names. I am worried about logical >> consistency. 'None' is something different, in fact quite opposite >> from 'Void'. 'Void' is the empty or "initial" domain. It is (should >> be) the result of an empty 'Union()'. 'Void' on the other hand is the >> empty product or "terminal" domain. It should be the result of an >> empty 'Record()' (or similar fundamental cross-product type). >> > > I am not sure what you mean here. Currently both 'None' and > 'Void' allow coercion from any domain, so both could be > candidates for "terminal" domain. For the domains in 'SetCategory' it does not make sense that there is an operation that maps values from some domain into 'None' since there are not supposed to be any values in 'None'. 'None' is an *initial* domain which means that for every domain X in 'SetCategory', there exists exactly one (trivial) operation with the signature 'None -> X'. > But 'None' is _not_ a terminal object: to have terminal object > you need unique mapping. I agree that 'None' is not a terminal object but 'Void' is a terminal object which just means that for every domain X in 'SetCategory' there exists a single unique (and trivial) operation with signature 'X->Void'. In fact any one-element domain in 'SetCategory' can be considered a terminal domain since then there is only one way to define an operation to produce such a value from any given domain. 'Void' is just singled-out as a canonical representative of all such domains. > In other words arrows must commute. I do not understand what you mean by commute in this context. > But we have: > > (22) -> pol := x^2 + 1 > > 2 > (22) x + 1 > Type: Polynomial(Integer) > (23) -> PRETTYPRINT(pol)$Lisp > (1 |x| (2 0 . 1) (0 0 . 1)) > > (23) () > Type: SExpression > (24) -> (pol::InputForm)::SEX > > (24) (+ (^ x 2) 1) > Type: SExpression > > Coercing to None will produce different values, and consequently > arrows do not commute. > Coercing something to 'None' is logically inconsistent. But there is always a unique way to map anything to 'Void'. Internally (inside Void) the representation of these values might be different but as long as equality is defined properly, externally they all represent the "same" value of 'Void'. > > Compiler internally needs to mark places where at first glance > we need or have value, but in fact there is no value. Compiler > could use some special marker to do this, but currently having > Void type is used for this purpose. If you allow real computation > on Void you will break this usage. What do you mean by "real computation". Is an operation such as (x:% = y:%) == true a real computation? Rather than being defined in the library this fact could simply be "known" to the compiler and no real computation would be necessary. > If you only provide operation which are consistent with 'Void' > being a terminal object, then I am not sure if you gain anything > (because you are still not able to get any nontrivial result) but > compiler will have some trouble handling trivialites. The properties of 'Void' as a domain in 'SetCategory' are important for the formal definition of 'SetCategory' as the (mathematical) category of sets. Although 'Void' itself is (mostly) trivial, the proper definition makes the definition of other not-so-trivial things possible. In principle I do not understand why the compiler should have trouble handling such trivialities, although in practice I think my current problem with defining 'Void' as a domain in 'SetCategory' is probably an example of such difficulties. Clearly if the definition of some domain is split between being at least partly built-in to the compiler and partly defined in the library, then these definitions must be consistent. >> ... >> However if all you want to do is (temporarily) ignore the type I do >> not see anything wrong with my proposal that we simply allow 'Void' to >> be non-canonical, i.e. >> >> terminal(x:X) == rep(x) pretend Void >> >> As long as we define equality as I did above this implementation >> remains logically consistent. > > It will be consistent if you do not allow anybody to discover > that values are different. But then, why to store them at > all? > Well, I did suggest that such an implementation of 'Void' is a logically consistent alternative to the current abuse of 'None'. I think that is a good reason. >> >> Why do you think 'Void' can not (or should not?) be used for this purpose? >> > > If you allow storing and retrieving values from 'Void' it no longer > will be terminal object (by the same reasoning which currently > applies to 'None') Retrieving values from 'Void' could only be done using 'pretend'. 'pretend' is a marker that something other than the usual operations of the library are required and that there is no inherent guarantee of (static) type-correctness. The need for 'pretend' in this case (and also as it is now currently implemented inconsistently using 'None') is to help deal with run-time types. >> ... >> 'None' fits mathematical category theory quite well as an initial object. >> >> http://en.wikipedia.org/wiki/Initial_and_terminal_objects >> > > This would be something quite different than our current 'None'. > Now, having real initial object may be nice from category > point of view, but I am not sure if it is useful for programming. > OTOH current 'None' is useful. > I think 'None' is currently useful only because it is implemented in an inconsistent manner. >> I think 'Any' is something else - the union of all domains >> >> Union( X for X in Domain) >> >> To implement this we need to know the values of 'Domain' and as Gaby >> implied, this means having to deal with the run time system in some >> way or another. As far as I can see this is currently done in Axiom >> via 'pretend' together with 'SExpression' and some magic from 'Lisp' >> to represent the run-time value of the type. I do not see any >> immediate reason to prefer >> >> per(x:None):% == x pretend X >> >> instead of >> >> per(x:Void):% == x pretend X >> >> In fact I think the first one is logically inconsistent. > > If you want categorical interpretation both seem wrong. > The second one because from terminal object you can have only > trivial arrows, which probably implies that X is trivial. I disagree. Each operation from a terminal object to some domain X represents an "element" of the domain X. This is not entirely trivial. > The first one may be consistent if None is really initial > object, but then it almost useless. > I do not understand why you think it makes sense to define an operation that by definition requires some input value from a domain that has no values. Regards, Bill Page. ------------------------------------------------------------------------------ Come build with us! The BlackBerry® Developer Conference in SF, CA is the only developer event you need to attend this year. Jumpstart your developing skills, take BlackBerry mobile applications to market and stay ahead of the curve. Join us from November 9-12, 2009. Register now! http://p.sf.net/sfu/devconf _______________________________________________ open-axiom-devel mailing list open-axiom-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/open-axiom-devel