MathExprs.mesa
Last Edited by Arnon: September 6, 1989 10:51:10 am PDT
Ground Domain corresponding to General Expressions
External rep is "Exprs"
DIRECTORY
Rope,
MathObjects,
MathStructures;
MathExprs: CEDAR DEFINITIONS
~ BEGIN
Types From Other Interfaces
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Object: TYPE = MathObjects.Object;
Element Representation
Expr: TYPE = Object;
ExprData: TYPE ~ REF ExprDataRep; -- external abstract type
ExprDataRep: TYPE; -- internal concrete rep
Domain Representation
None - no Domain-specific data
Element IO
EltFlavor: MathObjects.UnaryToRefOp; -- $flavor Method; returns $Element
EltDisplay1: MathBoxTrees.EltDisplayOp;
Unpack1: PROC [e: Expr] RETURNS [Results];
-- Private Unpack proc used by EltDisplay1.
EltDisplay2: MathBoxTrees.EltDisplayOp;
EltDisplay1, EltDisplay2, etc. are multiple display methods implementing multiple amounts of unpacking, different looking displays, etc. Each can be an Exprs Method, but with some more specific key than $eltDisplay.
EltDisplay: MathBoxTrees.EltDisplayOp;
The proc for the Exprs $eltDisplay method. It's an (Element) display "expert", i.e. it looks at the context coming in to an invocation of $eltDisplay, and then decides which of EltDisplay1, EltDisplay2, etc. to call, and with what context.
EltRead: MathObjects.ReadOp;
The Domain-dependent parser for general expressions. Assumes that args have been displayed with a EltToExprRope command, i.e. not their domain-dependent Ropes. Thus the Expr that it builds is "purely functional", i.e. args belong to domain Exprs at all levels.
Note that we cannot in general expect elements of domains to have a "natural" or "obvious" EltToExprRope form, especially the more complex the domain is. In general, there is a range between "storing (a pointer to) a finished object spec" in the Rope, i.e. specifying the domain, hence its parser, and just giving a (possibly terse and incomprehensible) Rope that that parser can use to rebuild the (mathematical) object as an element of that domain, and "storing abstract syntax" in the Rope, i.e. putting out something like pure functional form, with little or no domain indications, and leaving it to the system's (general expression evaluator's) type inference & resolution capabilities, and method lookup capabilities, to rebuild the object, if the need arises.
EltToRope: MathObjects.ToRopeOp;
Write out an Element in such a form that the Domain parser can read it back in.
EltFromRope: MathObjects.FromRopeOp;
LegalFirstChar: MathObjects.LegalFirstCharOp;
EltWrite: MathObjects.WriteOp;
Element Operations
EltEval: MathEnvironments.EvalOp;
Exprs.EltEval (applied to an Expr) is the general system evaluator. It is the basic "access point", or "user interface", to system method lookup and type resolution machinery.
The gist of it is:
EltEval: IF AtomicExpr THEN
Apply obvious rules, including substitution (and recursive call) for $symbol's that have bindings in e
ELSE
BEGIN -- CompositeExpr
[op, args] ← ... ;
eArgs ← MAP[$eval, args];
IF op = $assign OR op = $kill THEN {
make appropriate entry in newEnv;
RETURN[args.first, newEnv];
}; -- also catch $assign$ or $kill$; ERROR if firstArg no Exprs
IF op = $foo$ THEN -- see "convention" below
{key ← $foo; [hint, eArgs] ← [eArgs.first, eArgs.rest] }
ELSE {key ← op; hint ← NIL];
[value, newEnv] ← MathEnvironments.AttemptMethod[op, hint, eArgs, e];
{ if failure SIGNAL, then output a "functional" Expr, i.e. name[ ... argObjects ...] }
END;
A convenient convention EltEval assumes: when evaluating a CompositeExpr, whose args have been evaluated to a list "eArgs", then if method has the form $foo$ (or $foo←, or some such), then eArgs.first is taken to be a Structure S in which we are assured to find a Method $foo, such that eArgs.rest conforms to its staticType (i.e. right arity, all eArgs with Cedar types are type correct, Object eArgs may or may not be of correct type). Hence we can execute
[m,] ← LookupMethodInStructure[$foo, S, tryOther: FALSE, e];
result ← ApplyMethod[m, NIL, eArgs.rest, recast: TRUE];
and it will succeed iff eArgs.rest conforms to m's runtimeType, i.e. iff all Object eArgs can be suitably recast. If we don't succeed, then we are thrown back to the system's ability to find other methods $foo that possibly will succeed.
Element Conversions
WidenOther: MathObjects.BinaryOp;
Previously called "Recast"
Arguments are a DomainElement and a Domain. firstArg is intended to be an element of a "narrower" Domain than the one being defined by this interface, and secondArg is intended to be a Domain of the kind being defined by this interface. We attempt to widen firstArg to be an element of secondArg.
If CanWidenOther[firstArg], then either we return firstArg unchanged (it is already an element of secondArg), or we create and return a new Object belonging to secondArg, i.e. we never modify the input Object.
CanWidenOther: MathObjects.BinaryPredicate;
Previously called "CanRecast"
Arguments are either a DomainElement and a Domain, or two Domains. firstArg is intended to be an element of, or be, a "narrower" Domain than the one being defined by this interface, and secondArg is intended to be a Domain of the kind being defined by this interface. Returns true if firstArg can be widened to be an element of secondArg.
NarrowOther: MathObjects.BinaryOp;
Arguments are a DomainElement and a Domain. firstArg is intended to be an element of a "wider" Domain than the one being defined by this interface, and secondArg is intended to be a Domain of the kind being defined by this interface. We attempt to narrow firstArg to be an element of secondArg.
If CanNarrowOther[firstArg], then either we return firstArg unchanged (it is already an element of secondArg), or we create and return a new Object belonging to secondArg, i.e. we never modify the input Object.
CanNarrowOther: MathObjects.BinaryPredicate;
Arguments are either a DomainElement and a Domain, or two Domains. firstArg is intended to be an element of, or be, a "wider" Domain than the one being defined by this interface, and secondArg is intended to be a Domain of the kind being defined by this interface. Returns true if firstArg can be narrowed to be an element of secondArg.
WidenThis: MathObjects.UnaryOp;
Argument is a DomainElement belonging to a Domain of the kind being defined by this interface. Either we return it unchanged, or we widen it to be an element of some "wider" Domain. In the latter case, we create a new Object, i.e. don't modify input. However it is expected that only General Expressions could ever be returned unchanged by a WidenThis proc, since it should be possible to widen anything else into a General Expression.
For example, an integer can be widened to be a rational number.
Usually a (nontrivial) WidenThis proc is written by knowing some tag with which the intended domain can be looked up (so we don't need to mention the Cedar interface that defines it), and then just applying that Domain's WidenOther proc to the argument.
The basic AlgebraDomains method lookup procedure is to look for a method in this Object's class and all its superclasses, then set x ← WidenThis[input]; IF x.class.Equal[x, input] then FAIL else recursive call on x.
NarrowThis: MathObjects.UnaryOp;
Argument is a DomainElement belonging to a Domain of the kind being defined by this interface. Either we return it unchanged, or we narrow it to be an element of the narrowest possible "narrower" Domain. In the latter case, we create a new Object, i.e. don't modify input.
For example, the NarrowThis proc for the rational numbers should return a BigInt for 3/1, but (the unchanged input argument) BigRat for 3/5.
Expression evaluators are examples of NarrowThis procs. The fact that typically NarrowThis[V: Variable] looks for a value associated with V in some "environment", and if found, returns value.class.NarrowThis[value], is a detail that is entirely consistent with this assertion.
Element Constructors
MakeName: MathObjects.ListImbedOp;
Arguments are the fields of an ElementNameData.
MakeElementNameData: PROC [field1, field2] RETURNS [elementData: ElementNameData];
Element Selectors
GetNameElementData: MathObjects.GetElementDataProc;
MathObjects.GetElementDataProc: TYPE = PROC [domainElement: Object] RETURNS [ElementData: REF ANY];
output is a ElementNameData
Field1: MathObjects.UnaryOp;
Input is a domain, output is the field1 field of its ElementData (assuming this field is an Object)
Field2: MathObjects.UnaryOp;
Input is a domain, output is the field2 field of its ElementData (assuming this field is an Object)
Domain Constructors
DomMake: PROC RETURNS [domain: Object];
class = category = {Sets}
build methodDictionary
RETURN[MathObjects.MakeObject[class, [methodDictionary, NIL] ]
Domain Selectors
GetNameDomainData: MathObjects.GetDomainDataProc;
MathObjects.GetDomainDataProc: TYPE = PROC [domain: Object] RETURNS [DomainData: REF ANY];
output is a NameDomainData
Data1: MathObjects.UnaryOp;
Input is a domain, output is the data1 field of its DomainData (assuming this field is an Object)
Data2: MathObjects.UnaryOp;
Input is a domain, output is the data2 field of its DomainData (assuming this field is an Object)
Domain Operations
Flavor: MathObjects.FlavorOp;
MathObjects.FlavorOp: TYPE = PROC [object: Object] RETURNS [flavor: Flavor];
MathObjects.flavor: TYPE = { DomainElement, Domain, Class};
Looks (with ISTYPE) for ElementNameData and NameDomainData.
Should be in both DomainElement and Domain class records.
DomToRope: MathObjects.ToRopeOp;
A functional expression that can be parsed and evaluated to reconstruct the domain
DomName: MathObjects.ToRopeOp;
A short identifying name, e.g. "Q" for the rational numbers
DomLBKey: MathObjects.ToRopeOp;
LoganBerry primaryKey attribute value, for searching for this object in a LoganBerry db. Such keys are generated when an Object is to be offlined.
DomData: MathObjects.UnaryToListOp;
selector: returns LIST[data1, data2] of a Name Domain
IsNameDomain: MathObjects.UnaryPredicate;
END.