aboutsummaryrefslogtreecommitdiff
path: root/src/interp/i-coerce.boot.pamphlet
diff options
context:
space:
mode:
authordos-reis <gdr@axiomatics.org>2007-11-07 20:54:59 +0000
committerdos-reis <gdr@axiomatics.org>2007-11-07 20:54:59 +0000
commit4edaea6cff2d604009b8f2723a9436b0fc97895d (patch)
treeeb5d3765b2e4f131610571cf5f15eef53419fca0 /src/interp/i-coerce.boot.pamphlet
parent45ce0071c30e84b72e4c603660285fa6a462e7f7 (diff)
downloadopen-axiom-4edaea6cff2d604009b8f2723a9436b0fc97895d.tar.gz
remove more pamphlets
Diffstat (limited to 'src/interp/i-coerce.boot.pamphlet')
-rw-r--r--src/interp/i-coerce.boot.pamphlet1442
1 files changed, 0 insertions, 1442 deletions
diff --git a/src/interp/i-coerce.boot.pamphlet b/src/interp/i-coerce.boot.pamphlet
deleted file mode 100644
index b488ce9d..00000000
--- a/src/interp/i-coerce.boot.pamphlet
+++ /dev/null
@@ -1,1442 +0,0 @@
-\documentclass{article}
-\usepackage{axiom}
-
-\title{\File{src/interp/i-coerce.boot} Pamphlet}
-\author{The Axiom Team}
-
-\begin{document}
-\maketitle
-\begin{abstract}
-\end{abstract}
-\eject
-\tableofcontents
-\eject
-
-\section{Coercion conventions}
-
-\begin{verbatim}
-Coercion conventions
-
-Coercion involves the changing of the datatype of an object. This
- can be done for conformality of operations or, for example, to
- change the structure of an object into one that is understood by
- the printing routines.
-
-The actual coercion is controlled by the function "coerce" which
- takes and delivers wrapped operands. Also see the functions
- interpCoerce and coerceInteractive.
-
-Sometimes one does not want to actually change the datatype but
- rather wants to determine whether it is possible to do so. The
- controlling function to do this is "canCoerceFrom". The value
- passed to specific coercion routines in this case is
- "$fromCoerceable$". The value returned is true or false. See
- specific examples for more info.
-
-The special routines that do the coercions typically involve a "2"
- in their names. For example, G2E converts type "Gaussian" to
- type "Expression". These special routines take and deliver
- unwrapped operands. The determination of which special routine
- to use is often made by consulting the list $CoerceTable
- (currently in COT BOOT) and this is controlled by coerceByTable.
- Note that the special routines are in the file COERCEFN BOOT.
-\end{verbatim}
-\section{Function getConstantFromDomain}
-[[getConstantFromDomain]] is used to look up the constants $0$ and $1$
-from the given [[domainForm]].
-\begin{enumerate}
-\item if [[isPartialMode]] (see i-funsel.boot) returns true then the
-domain modemap contains the constant [[$EmptyMode]] which indicates
-that the domain is not fully formed. In this case we return [[NIL]].
-\end{enumerate}
-<<getConstantFromDomain>>=
-getConstantFromDomain(form,domainForm) ==
- isPartialMode domainForm => NIL
- opAlist := getOperationAlistFromLisplib first domainForm
- key := opOf form
- entryList := LASSOC(key,opAlist)
- entryList isnt [[sig, ., ., .]] =>
- key = "One" => getConstantFromDomain(["1"], domainForm)
- key = "Zero" => getConstantFromDomain(["0"], domainForm)
- throwKeyedMsg("S2IC0008",[form,domainForm])
- -- i.e., there should be exactly one item under this key of that form
- domain := evalDomain domainForm
- SPADCALL compiledLookupCheck(key,sig,domain)
-
-@
-\section{License}
-<<license>>=
--- Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--- All rights reserved.
---
--- Redistribution and use in source and binary forms, with or without
--- modification, are permitted provided that the following conditions are
--- met:
---
--- - Redistributions of source code must retain the above copyright
--- notice, this list of conditions and the following disclaimer.
---
--- - Redistributions in binary form must reproduce the above copyright
--- notice, this list of conditions and the following disclaimer in
--- the documentation and/or other materials provided with the
--- distribution.
---
--- - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--- names of its contributors may be used to endorse or promote products
--- derived from this software without specific prior written permission.
---
--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-@
-<<*>>=
-<<license>>
-
-import '"i-analy"
-import '"i-resolv"
-)package "BOOT"
-
---% Algebraic coercions using interactive code
-
-algCoerceInteractive(p,source,target) ==
- -- now called in some groebner code
- $useConvertForCoercions : local := true
- source := devaluate source
- target := devaluate target
- u := coerceInteractive(objNewWrap(p,source),target)
- u => objValUnwrap(u)
- error ['"can't convert",p,'"of mode",source,'"to mode",target]
-
-spad2BootCoerce(x,source,target) ==
- -- x : source and we wish to coerce to target
- -- used in spad code for Any
- null isValidType source => throwKeyedMsg("S2IE0004",[source])
- null isValidType target => throwKeyedMsg("S2IE0004",[target])
- x' := coerceInteractive(objNewWrap(x,source),target) =>
- objValUnwrap(x')
- throwKeyedMsgCannotCoerceWithValue(wrap x,source,target)
-
---% Functions for Coercion or Else We'll Get Rough
-
-coerceOrFail(triple,t,mapName) ==
- -- some code generated for this is in coerceInt0
- t = $NoValueMode => triple
- t' := coerceInteractive(triple,t)
- t' => objValUnwrap(t')
- sayKeyedMsg("S2IC0004",[mapName,objMode triple,t])
- '"failed"
-
-coerceOrCroak(triple, t, mapName) ==
- -- this does the coercion and returns the value or dies
- t = $NoValueMode => triple
- t' := coerceOrConvertOrRetract(triple,t)
- t' => objValUnwrap(t')
- mapName = 'noMapName =>
- throwKeyedMsgCannotCoerceWithValue(objVal triple,objMode triple, t)
- sayKeyedMsg("S2IC0005",[mapName])
- throwKeyedMsgCannotCoerceWithValue(objVal triple,objMode triple, t)
-
-coerceOrThrowFailure(value, t1, t2) ==
- (result := coerceOrRetract(objNewWrap(value, t1), t2)) or
- coercionFailure()
- objValUnwrap(result)
-
---% Retraction functions
-
-retract object ==
- type := objMode object
- STRINGP type => 'failed
- type = $EmptyMode => 'failed
- val := objVal object
- not isWrapped val and val isnt ['MAP,:.] => 'failed
- type' := equiType(type)
- (ans := retract1 objNew(val,equiType(type))) = 'failed => ans
- objNew(objVal ans,eqType objMode ans)
-
-retract1 object ==
- -- this function is the new version of the old "pullback"
- -- it first tries to change the datatype of an object to that of
- -- largest contained type. Examples: P RN -> RN, RN -> I
- -- This is mostly for cases such as constant polynomials or
- -- quotients with 1 in the denominator.
- type := objMode object
- STRINGP type => 'failed
- val := objVal object
- type = $PositiveInteger => objNew(val,$NonNegativeInteger)
- type = $NonNegativeInteger => objNew(val,$Integer)
- type = $Integer and SINTP unwrap val => objNew(val, $SingleInteger)
- type' := equiType(type)
- if not EQ(type,type') then object := objNew(val,type')
- (1 = #type') or (type' is ['Union,:.]) or
- (type' is ['FunctionCalled,.])
- or (type' is ['OrderedVariableList,.]) or (type is ['Variable,.]) =>
- (object' := retract2Specialization(object)) => object'
- 'failed
- null (underDomain := underDomainOf type') => 'failed
- -- try to retract the "coefficients"
- -- think of P RN -> P I or M RN -> M I
- object' := retractUnderDomain(object,type,underDomain)
- object' ^= 'failed => object'
- -- see if we can use the retract functions
- (object' := coerceRetract(object,underDomain)) => object'
- -- see if we have a special case here
- (object' := retract2Specialization(object)) => object'
- 'failed
-
-retractUnderDomain(object,type,underDomain) ==
- null (ud := underDomainOf underDomain) => 'failed
- [c,:args] := deconstructT type
- 1 ^= #args => 'failed
- 1 ^= #c => 'failed
- type'' := constructT(c,[ud])
- (object' := coerceInt(object,type'')) => object'
- 'failed
-
-retract2Specialization object ==
- -- handles some specialization retraction cases, like matrices
- val := objVal object
- val' := unwrap val
- type := objMode object
-
- type = $Any =>
- [dom,:obj] := val'
- objNewWrap(obj,dom)
- type is ['Union,:unionDoms] => coerceUnion2Branch object
- type = $Symbol =>
- objNewWrap(1,['OrderedVariableList,[val']])
- type is ['OrderedVariableList,var] =>
- coerceInt(objNewWrap(var.(val'-1),$Symbol), '(Polynomial (Integer)))
--- !! following retract seems wrong and breaks ug13.input
--- type is ['Variable,var] =>
--- coerceInt(object,$Symbol)
- type is ['Polynomial,D] =>
- val' is [ =1,x,:.] =>
- vl := REMDUP reverse varsInPoly val'
- 1 = #vl => coerceInt(object,['UnivariatePolynomial,x,D])
- NIL
- val' is [ =0,:.] => coerceInt(object, D)
- NIL
- type is ['Matrix,D] =>
- n := # val'
- m := # val'.0
- n = m => objNew(val,['SquareMatrix,n,D])
- objNew(val,['RectangularMatrix,n,m,D])
- type is ['RectangularMatrix,n,m,D] =>
- n = m => objNew(val,['SquareMatrix,n,D])
- NIL
- (type is [agg,D]) and (agg in '(Vector Segment UniversalSegment)) =>
- D = $PositiveInteger => objNew(val,[agg,$NonNegativeInteger])
- D = $NonNegativeInteger => objNew(val,[agg,$Integer])
- NIL
- type is ['Array,bds,D] =>
- D = $PositiveInteger => objNew(val,['Array,bds,$NonNegativeInteger])
- D = $NonNegativeInteger => objNew(val,['Array,bds,$Integer])
- NIL
- type is ['List,D] =>
- D isnt ['List,D'] =>
- -- try to retract elements
- D = $PositiveInteger => objNew(val,['List,$NonNegativeInteger])
- D = $NonNegativeInteger => objNew(val,['List,$Integer])
- null val' => nil
--- null (um := underDomainOf D) => nil
--- objNewWrap(nil,['List,um])
- vl := nil
- tl := nil
- bad := nil
- for e in val' while not bad repeat
- (e' := retract objNewWrap(e,D)) = 'failed => bad := true
- vl := [objValUnwrap e',:vl]
- tl := [objMode e',:tl]
- bad => NIL
- (m := resolveTypeListAny tl) = D => NIL
- D = equiType(m) => NIL
- vl' := nil
- for e in vl for t in tl repeat
- t = m => vl' := [e,:vl']
- e' := coerceInt(objNewWrap(e,t),m)
- null e' => return NIL
- vl' := [objValUnwrap e',:vl']
- objNewWrap(vl',['List,m])
- D' = $PositiveInteger =>
- objNew(val,['List,['List,$NonNegativeInteger]])
- D' = $NonNegativeInteger =>
- objNew(val,['List,['List,$Integer]])
- D' is ['Variable,.] or D' is ['OrderedVariableList,.] =>
- coerceInt(object,['List,['List,$Symbol]])
-
- n := # val'
- m := # val'.0
- null isRectangularList(val',n,m) => NIL
- coerceInt(object,['Matrix,D'])
- type is ['Expression,D] =>
- [num,:den] := val'
- -- coerceRetract already handles case where den = 1
- num isnt [0,:num] => NIL
- den isnt [0,:den] => NIL
- objNewWrap([num,:den],[$QuotientField, D])
- type is ['SimpleAlgebraicExtension,k,rep,.] =>
- -- try to retract as an element of rep and see if we can get an
- -- element of k
- val' := retract objNew(val,rep)
- while (val' ^= 'failed) and
- (equiType(objMode val') ^= k) repeat
- val' := retract val'
- val' = 'failed => NIL
- val'
-
- type is ['UnivariatePuiseuxSeries, coef, var, cen] =>
- coerceInt(object, ['UnivariateLaurentSeries, coef, var, cen])
- type is ['UnivariateLaurentSeries, coef, var, cen] =>
- coerceInt(object, ['UnivariateTaylorSeries, coef, var, cen])
-
- type is ['FunctionCalled,name] =>
- null (m := get(name,'mode,$e)) => NIL
- isPartialMode m => NIL
- objNew(val,m)
- NIL
-
-coerceOrConvertOrRetract(T,m) ==
- $useConvertForCoercions : local := true
- coerceOrRetract(T,m)
-
-coerceOrRetract(T,m) ==
- (t' := coerceInteractive(T,m)) => t'
- t := T
- ans := nil
- repeat
- ans => return ans
- t := retract t -- retract is new name for pullback
- t = 'failed => return ans
- ans := coerceInteractive(t,m)
- ans
-
-coerceRetract(object,t2) ==
- -- tries to handle cases such as P I -> I
- (val := objValUnwrap(object)) = "$fromCoerceable$" => NIL
- t1 := objMode object
- t2 = $OutputForm => NIL
- isEqualOrSubDomain(t1,$Integer) and typeIsASmallInteger(t2) and SMINTP(val) =>
- objNewWrap(val,t2)
- t1 = $Integer => NIL
- t1 = $Symbol => NIL
- t1 = $OutputForm => NIL
- (c := retractByFunction(object, t2)) => c
- t1 is [D,:.] =>
- fun := GETL(D,'retract) or
- INTERN STRCONC('"retract",STRINGIMAGE D)
- functionp fun =>
- PUT(D,'retract,fun)
- c := CATCH('coerceFailure,FUNCALL(fun,object,t2))
- (c = $coerceFailure) => NIL
- c
- NIL
- NIL
-
-retractByFunction(object,u) ==
- -- tries to retract by using function "retractIfCan"
- -- if the type belongs to the correct category.
- $reportBottomUpFlag: local := NIL
- t := objMode object
- -- JHD/CRF not ofCategory(t,['RetractableTo,u]) => NIL
- val := objValUnwrap object
-
- -- try to get and apply the function "retractable?"
- target := ['Union,u,'"failed"]
- funName := 'retractIfCan
- if $reportBottomUpFlag then
- sayFunctionSelection(funName,[t],target,NIL,
- '"coercion facility (retraction)")
- -- JHD/CRF if (mms := findFunctionInDomain(funName,t,target,[t],[t],'T,'T))
- -- MCD: changed penultimate variable to NIL.
- if (mms := append(findFunctionInDomain(funName,t,target,[t],[t],NIL,'T),
- findFunctionInDomain(funName,u,target,[t],[t],NIL,'T)))
--- The above two lines were: (RDJ/BMT 6/95)
--- if (mms := append(findFunctionInDomain(funName,t,target,[t],[t],'T,'T),
--- findFunctionInDomain(funName,u,target,[t],[t],'T,'T)))
- then mms := orderMms(funName,mms,[t],[t],target)
- if $reportBottomUpFlag then
- sayFunctionSelectionResult(funName,[t],mms)
- null mms => NIL
-
- -- [[dc,:.],slot,.]:= CAR mms
- dc := CAAAR mms
- slot := CADAR mms
- dcVector:= evalDomain dc
- fun :=
---+
- compiledLookup(funName,[target,t],dcVector)
- NULL fun => NIL
- CAR(fun) = function Undef => NIL
---+
- $: fluid := dcVector
- object' := coerceUnion2Branch objNewWrap(SPADCALL(val,fun),target)
- u' := objMode object'
- u = u' => object'
- NIL
-
---% Coercion utilities
-
--- The next function extracts the structural definition of constants
--- from a given domain. For example, getConstantFromDomain('(One),S)
--- returns the representation of 1 in the domain S.
-
-constantInDomain?(form,domainForm) ==
- opAlist := getOperationAlistFromLisplib first domainForm
- key := opOf form
- entryList := LASSOC(key,opAlist)
- entryList is [[., ., ., type]] and type in '(CONST ASCONST) => true
- key = "One" => constantInDomain?(["1"], domainForm)
- key = "Zero" => constantInDomain?(["0"], domainForm)
- false
-
-<<getConstantFromDomain>>
-
-domainOne(domain) == getConstantFromDomain('(One),domain)
-
-domainZero(domain) == getConstantFromDomain('(Zero),domain)
-
-equalOne(object, domain) ==
- -- tries using constant One and "=" from domain
- -- object should not be wrapped
- algEqual(object, getConstantFromDomain('(One),domain), domain)
-
-equalZero(object, domain) ==
- -- tries using constant Zero and "=" from domain
- -- object should not be wrapped
- algEqual(object, getConstantFromDomain('(Zero),domain), domain)
-
-algEqual(object1, object2, domain) ==
- -- sees if 2 objects of the same domain are equal by using the
- -- "=" from the domain
- -- objects should not be wrapped
--- eqfunc := getFunctionFromDomain("=",domain,[domain,domain])
- eqfunc := compiledLookupCheck("=",[$Boolean,'$,'$],evalDomain domain)
- SPADCALL(object1,object2, eqfunc)
-
---% main algorithms for canCoerceFrom and coerceInteractive
-
--- coerceInteractive and canCoerceFrom are the two coercion functions
--- for $InteractiveMode. They translate RN, RF and RR to QF I, QF P
--- and RE RN, respectively, and call coerceInt or canCoerce, which
--- both work in the same way (e.g. coercion from t1 to t2):
-
--- 1. they try to coerce t1 to t2 directly (tower coercion), and, if
--- this fails, to coerce t1 to the last argument of t2 and embed
--- this last argument into t2. These embedding functions are now only
--- defined in the algebra code. (RSS 2-27-87)
-
--- 2. the tower coercion looks whether there is any applicable local
--- coercion, which means, one defined in boot or in algebra code.
--- If there is an applicable function from a constructor, which is
--- inside the type tower of t1, to the top level constructor of t2,
--- then this constructor is bubbled up inside t1. This means,
--- special coercion functions (defined in boot) are called, which
--- commute two constructors in a tower. Then the local coercion is
--- called on these constructors, which both are on top level now.
-
--- example:
--- let t1 = A B C D E (short for (A (B (C (D (E))))), where A ... E are
--- type constructors), and t2 = F D G H I J
--- there is no coercion from t1 to t2 directly, so we try to coerce
--- t1 to s1 = D G H I J, the last argument of t2
--- we create the type s2 = A D B C E and call a local coercion A2A
--- from t1 to s2, which, by recursively calling coerce, bubbles up
--- the constructor D
--- then we call a commute coerce from s2 to s3 = D A B C E and a local
--- coerce D2D from s3 to s1
--- finally we embed s1 into t2, which completes the coercion t1 to t2
-
--- the result of canCoerceFrom is TRUE or NIL
--- the result of coerceInteractive is a object or NIL (=failed)
--- all boot coercion functions have the following result:
--- 1. if u=$fromCoerceable$, then TRUE or NIL
--- 2. if the coercion succeeds, the coerced value (this may be NIL)
--- 3. if the coercion fails, they throw to a catch point in
--- coerceByFunction
-
---% Interpreter Coercion Query Functions
-
-canCoerce1(t1,t2) ==
- -- general test for coercion
- -- the result is NIL if it fails
- t1 = t2 => true
- absolutelyCanCoerceByCheating(t1,t2) or t1 = '(None) or t2 = '(Any) or
- t1 in '((Mode) (Domain) (SubDomain (Domain))) =>
- t2 = $OutputForm => true
- NIL
- -- next is for tagged union selectors for the time being
- t1 is ['Variable,=t2] or t2 is ['Variable,=t1] => true
- STRINGP t1 =>
- t2 = $String => true
- t2 = $OutputForm => true
- t2 is ['Union,:.] => canCoerceUnion(t1,t2)
- t2 is ['Variable,v] and (t1 = PNAME(v)) => true
- NIL
- STRINGP t2 =>
- t1 is ['Variable,v] and (t2 = PNAME(v)) => true
- NIL
- atom t1 or atom t2 => NIL
- null isValidType(t2) => NIL
-
- absolutelyCannotCoerce(t1,t2) => NIL
-
- nt1 := CAR t1
- nt2 := CAR t2
-
- EQ(nt1,'Mapping) => EQ(nt2,'Any)
- EQ(nt2,'Mapping) =>
- EQ(nt1,'Variable) or EQ(nt1,'FunctionCalled) =>
- canCoerceExplicit2Mapping(t1,t2)
- NIL
- EQ(nt1,'Union) or EQ(nt2,'Union) => canCoerceUnion(t1,t2)
-
- -- efficiency hack
- t1 is ['Segment, s1] and t2 is ['UniversalSegment, s2] and
- (isEqualOrSubDomain(s1, s2) or canCoerce(s1, s2)) => true
-
- t1 is ['Tuple,S] and t2 ^= '(OutputForm) => canCoerce(['List, S], t2)
-
- isRingT2 := ofCategory(t2,'(Ring))
- isRingT2 and isEqualOrSubDomain(t1,$Integer) => true
- (ans := canCoerceTopMatching(t1,t2,nt1,nt2)) ^= 'maybe => ans
- t2 = $Integer => canCoerceLocal(t1,t2) -- is true
- ans := canCoerceTower(t1,t2) or
- [.,:arg]:= deconstructT t2
- arg and
- t:= last arg
- canCoerce(t1,t) and canCoerceByFunction(t,t2) and 'T
- ans or (t1 in '((PositiveInteger) (NonNegativeInteger))
- and canCoerce($Integer,t2))
-
-canCoerceFrom0(t1,t2) ==
--- top level test for coercion, which transfers all RN, RF and RR into
--- equivalent types
- startTimingProcess 'querycoerce
- q :=
- isEqualOrSubDomain(t1,t2) or t1 = '(None) or t2 = '(Any) or
- if t2 = $OutputForm then (s1 := t1; s2 := t2)
- else (s1:= equiType(t1); s2:= equiType(t2))
-
- -- make sure we are trying to coerce to a legal type
- -- in particular, polynomials are repeated, etc.
- null isValidType(t2) => NIL
- null isLegitimateMode(t2,nil,nil) => NIL
-
- t1 = $RationalNumber =>
- isEqualOrSubDomain(t2,$Integer) => NIL
- canCoerce(t1,t2) or canCoerce(s1,s2)
- canCoerce(s1,s2)
- stopTimingProcess 'querycoerce
- q
-
-isSubTowerOf(t1,t2) ==
- -- assumes RF and RN stuff has been expanded
- -- tests whether t1 is somewhere inside t2
- isEqualOrSubDomain(t1,t2) => true
- null (u := underDomainOf t2) => nil
- isSubTowerOf(t1,u)
-
-canCoerceTopMatching(t1,t2,tt1,tt2) ==
- -- returns true, nil or maybe
- -- for example, if t1 = P[x] D1 and t2 = P[y] D2 and x = y then
- -- canCoerce will only be true if D1 = D2
- not EQ(tt1,tt2) => 'maybe
- doms := '(Polynomial List Matrix FiniteSet Vector Stream Gaussian)
- MEMQ(tt1,doms) => canCoerce(CADR t1, CADR t2)
- not (MEMQ(tt1,$univariateDomains) or MEMQ(tt2,$multivariateDomains)) =>
- 'maybe
- u2 := deconstructT t2
- 1 = #u2 => NIL
- u1 := deconstructT t1
- 1 = #u1 => NIL -- no under domain
- first(u1) ^= first(u2) => 'maybe
- canCoerce(underDomainOf t1, underDomainOf t2)
-
-canCoerceExplicit2Mapping(t1,t is ['Mapping,target,:argl]) ==
- -- determines if there a mapping called var with the given args
- -- and target
- $useCoerceOrCroak: local := nil
- t1 is ['Variable,var] =>
- null (mms :=selectMms1(var,target,argl,[NIL for a in argl],true)) => NIL
- mm := CAAR mms
- mm is [., targ, :.] =>
- targ = target => true
- false
- false
- t1 is ['FunctionCalled,fun] =>
- funNode := mkAtreeNode fun
- transferPropsToNode(fun,funNode)
- mms := CATCH('coerceOrCroaker, selectLocalMms(funNode,fun,argl,target))
- CONSP mms =>
- mms is [[['interpOnly,:.],:.]] => nil
- mm := CAAR mms
- mm is [., targ, :.] =>
- targ = target => true
- false
- false
- NIL
- NIL
-
-canCoerceUnion(t1,t2) ==
- -- sees if one can coerce to or from a Union Domain
- -- assumes one of t1 and t2 is one
-
- -- get the domains in the union, checking for tagged unions
- if (isUnion1 := t1 is ['Union,:uds1]) then
- unionDoms1 :=
- uds1 and first uds1 is [":",:.] => [t for [.,.,t] in uds1]
- uds1
- if (isUnion2 := t2 is ['Union,:uds2]) then
- unionDoms2 :=
- uds2 and first uds2 is [":",:.] => [t for [.,.,t] in uds2]
- uds2
-
- isUnion2 =>
- member(t1,unionDoms2) => true
- isUnion1 =>
- and/[or/[canCoerce(ud1,ud2) for ud2 in unionDoms2]
- for ud1 in unionDoms1]
- or/[canCoerce(t1,ud) for ud in unionDoms2]
- -- next, a little lie
- t1 is ['Union,d1, ='"failed"] and t2 = d1 => true
- isUnion1 =>
- and/[canCoerce(ud,t2) for ud in unionDoms1]
- keyedSystemError("S2GE0016",['"canCoerceUnion",
- '"called with 2 non-Unions"])
-
-canCoerceByMap(t1,t2) ==
- -- idea is this: if t1 is D U1 and t2 is D U2, then look for
- -- map: (U1 -> U2, D U1) -> D U2. If it exists, then answer true
- -- if canCoerceFrom(t1,t2).
- u2 := deconstructT t2
- 1 = #u2 => NIL
- u1 := deconstructT t1
- 1 = #u1 => NIL -- no under domain
- CAR(u1) ^= CAR(u2) => NIL
- top := CAAR u1
- u1 := underDomainOf t1
- u2 := underDomainOf t2
-
- absolutelyCannotCoerce(u1,u2) => NIL
-
- -- save some time for those we know about
- know := '(List Vector Segment Stream UniversalSegment Array
- Polynomial UnivariatePolynomial SquareMatrix Matrix)
- top in know => canCoerce(u1,u2)
-
- null selectMms1('map,t2,[['Mapping,u2,u1],t1],
- [['Mapping,u2,u1],u1],NIL) => NIL
- -- don't bother checking for Undef, so avoid instantiation
- canCoerce(u1,u2)
-
-canCoerceTower(t1,t2) ==
--- tries to find a coercion between top level t2 and somewhere inside t1
--- builds new bubbled type, for which coercion is called recursively
- canCoerceByMap(t1,t2) or newCanCoerceCommute(t1,t2) or
- canCoerceLocal(t1,t2) or canCoercePermute(t1,t2) or
- [c1,:arg1]:= deconstructT t1
- arg1 and
- TL:= NIL
- arg:= arg1
- until x or not arg repeat x:=
- t:= last arg
- [c,:arg]:= deconstructT t
- TL:= [c,arg,:TL]
- arg and coerceIntTest(t,t2) and
- CDDR TL =>
- s:= constructT(c1,replaceLast(arg1,bubbleConstructor TL))
- canCoerceLocal(t1,s) and
- [c2,:arg2]:= deconstructT last s
- s1:= bubbleConstructor [c2,arg2,c1,arg1]
- canCoerceCommute(s,s1) and canCoerceLocal(s1,t2)
- s:= bubbleConstructor [c,arg,c1,arg1]
- newCanCoerceCommute(t1,s) and canCoerceLocal(s,t2)
- x
-
-canCoerceLocal(t1,t2) ==
- -- test for coercion on top level
- p:= ASSQ(CAR t1,$CoerceTable)
- p and ASSQ(CAR t2,CDR p) is [.,:[tag,fun]] =>
- tag='partial => NIL
- tag='total => true
- (functionp(fun) and
- (v:=CATCH('coerceFailure,FUNCALL(fun,'_$fromCoerceable_$,t1,t2)))
- and v ^= $coerceFailure) or canCoerceByFunction(t1,t2)
- canCoerceByFunction(t1,t2)
-
-canCoerceCommute(t1,t2) ==
--- THIS IS OUT-MODED AND WILL GO AWAY SOON RSS 2-87
--- t1 is t2 with the two top level constructors commuted
--- looks for the existence of a commuting function
- CAR(t1) in (l := [$QuotientField, 'Gaussian]) and
- CAR(t2) in l => true
- p:= ASSQ(CAR t1,$CommuteTable)
- p and ASSQ(CAR t2,CDR p) is [.,:['commute,.]]
-
-newCanCoerceCommute(t1,t2) ==
- coerceIntCommute(objNewWrap("$fromCoerceable$",t1),t2)
-
-canCoercePermute(t1,t2) ==
- -- try to generate a sequence of transpositions that will convert
- -- t1 into t2
- t2 in '((Integer) (OutputForm)) => NIL
- towers := computeTTTranspositions(t1,t2)
- -- at this point, CAR towers = t1 and last towers should be similar
- -- to t2 in the sense that the components of t1 are in the same order
- -- as in t2. If length towers = 2 and t2 = last towers, we quit to
- -- avoid an infinte loop.
- NULL towers or NULL CDR towers => NIL
- NULL CDDR towers and t2 = CADR towers => NIL
- -- do the coercions successively, quitting if any fail
- ok := true
- for t in CDR towers while ok repeat
- ok := canCoerce(t1,t)
- if ok then t1 := t
- ok
-
-canConvertByFunction(m1,m2) ==
- null $useConvertForCoercions => NIL
- canCoerceByFunction1(m1,m2,'convert)
-
-canCoerceByFunction(m1,m2) == canCoerceByFunction1(m1,m2,'coerce)
-
-canCoerceByFunction1(m1,m2,fun) ==
- -- calls selectMms with $Coerce=NIL and tests for required target=m2
- $declaredMode:local:= NIL
- $reportBottomUpFlag:local:= NIL
- -- have to handle cases where we might have changed from RN to QF I
- -- make 2 lists of expanded and unexpanded types
- l1 := REMDUP [m1,eqType m1]
- l2 := REMDUP [m2,eqType m2]
- ans := NIL
- for t1 in l1 while not ans repeat
- for t2 in l2 while not ans repeat
- l := selectMms1(fun,t2,[t1],[t1],NIL)
- ans := [x for x in l | x is [sig,:.] and CADR sig=t2 and
- CADDR sig=t1 and
- CAR(sig) isnt ['TypeEquivalence,:.]] and true
- ans
-
-absolutelyCanCoerceByCheating(t1,t2) ==
- -- this typically involves subdomains and towers where the only
- -- difference is a subdomain
- isEqualOrSubDomain(t1,t2) => true
- typeIsASmallInteger(t1) and t2 = $Integer => true
- ATOM(t1) or ATOM(t2) => false
- [tl1,:u1] := deconstructT t1
- [tl2,:u2] := deconstructT t2
- tl1 = '(Stream) and tl2 = '(InfiniteTuple) =>
- #u1 ^= #u2 => false
- "and"/[absolutelyCanCoerceByCheating(x1,x2) for x1 in u1 for x2 in u2]
- tl1 ^= tl2 => false
- #u1 ^= #u2 => false
- "and"/[absolutelyCanCoerceByCheating(x1,x2) for x1 in u1 for x2 in u2]
-
-absolutelyCannotCoerce(t1,t2) ==
- -- response of true means "definitely cannot coerce"
- -- this is largely an efficiency hack
- ATOM(t1) or ATOM(t2) => NIL
- t2 = '(None) => true
- n1 := CAR t1
- n2 := CAR t2
- QFI := [$QuotientField, $Integer]
- int2 := isEqualOrSubDomain(t2,$Integer)
- scalars := '(BigFloat NewFloat Float DoubleFloat RationalNumber)
-
- MEMQ(n1,scalars) and int2 => true
- (t1 = QFI) and int2 => true
-
- num2 := int2 or MEMQ(n2,scalars) or (t2 = QFI)
- isVar1 := MEMQ(n1,'(Variable Symbol))
-
- num2 and isVar1 => true
- num2 and MEMQ(n1,$univariateDomains) => true
- num2 and MEMQ(n1,$multivariateDomains) => true
- miscpols := '(Polynomial ElementaryFunction SimpleAlgebraicExtension)
- num2 and MEMQ(n1,miscpols) => true
-
- aggs := '(
- Matrix List Vector Stream Array RectangularMatrix FiniteSet
- )
- u1 := underDomainOf t1
- u2 := underDomainOf t2
- MEMQ(n1,aggs) and (u1 = t2) => true
- MEMQ(n2,aggs) and (u2 = t1) => true
-
- algs := '(
- SquareMatrix Gaussian RectangularMatrix Quaternion
- )
- nonpols := append(aggs,algs)
- num2 and MEMQ(n1,nonpols) => true
- isVar1 and MEMQ(n2,nonpols) and
- absolutelyCannotCoerce(t1,u2) => true
-
- (MEMQ(n1,scalars) or (t1 = QFI)) and (t2 = '(Polynomial (Integer))) =>
- true
-
- v2 := deconstructT t2
- 1 = #v2 => NIL
- v1 := deconstructT t1
- 1 = #v1 => NIL
- CAR(v1) ^= CAR(v2) => NIL
- absolutelyCannotCoerce(u1,u2)
-
-typeIsASmallInteger x == (x = $SingleInteger)
-
-
---% Interpreter Coercion Functions
-
-coerceInteractive(triple,t2) ==
- -- bind flag for recording/reporting instantiations
- -- (see recordInstantiation)
- t1 := objMode triple
- val := objVal triple
- null(t2) or t2 = $EmptyMode => NIL
- t2 = t1 => triple
- t2 = '$NoValueMode => objNew(val,t2)
- if t2 is ['SubDomain,x,.] then t2:= x
- -- JHD added category Aug 1996 for BasicMath
- t1 in '((Category) (Mode) (Domain) (SubDomain (Domain))) =>
- t2 = $OutputForm => objNew(val,t2)
- NIL
- t1 = '$NoValueMode =>
- if $compilingMap then clearDependentMaps($mapName,nil)
- throwKeyedMsg("S2IC0009",[t2,$mapName])
- $insideCoerceInteractive: local := true
- expr2 := EQUAL(t2,$OutputForm)
- if expr2 then startTimingProcess 'print
- else startTimingProcess 'coercion
- -- next 2 lines handle cases like '"failed"
- result :=
- expr2 and (t1 = val) => objNew(val,$OutputForm)
- expr2 and t1 is ['Variable,var] => objNewWrap(var,$OutputForm)
- coerceInt0(triple,t2)
- if expr2 then stopTimingProcess 'print
- else stopTimingProcess 'coercion
- result
-
-coerceInt0(triple,t2) ==
- -- top level interactive coercion, which transfers all RN, RF and RR
- -- into equivalent types
- val := objVal triple
- t1 := objMode triple
-
- val='_$fromCoerceable_$ => canCoerceFrom(t1,t2)
- t1 = t2 => triple
- if t2 = $OutputForm then
- s1 := t1
- s2 := t2
- else
- s1 := equiType(t1)
- s2 := equiType(t2)
- s1 = s2 => return objNew(val,t2)
- -- t1 is ['Mapping,:.] and t2 ^= '(Any) => NIL
- -- note: may be able to coerce TO mapping
- -- treat Exit like Any
- -- handle case where we must generate code
- null(isWrapped val) and
- (t1 isnt ['FunctionCalled,:.] or not $genValue)=>
- intCodeGenCOERCE(triple,t2)
- t1 = $Any and t2 ^= $OutputForm and ([t1',:val'] := unwrap val) and
- (ans := coerceInt0(objNewWrap(val',t1'),t2)) => ans
- if not EQ(s1,t1) then triple := objNew(val,s1)
- x := coerceInt(triple,s2) =>
- EQ(s2,t2) => x
- objSetMode(x,t2)
- x
- NIL
-
-coerceInt(triple, t2) ==
- val := coerceInt1(triple, t2) => val
- t1 := objMode triple
- t1 is ['Variable, :.] =>
- newMode := getMinimalVarMode(unwrap objVal triple, nil)
- newVal := coerceInt(triple, newMode)
- coerceInt(newVal, t2)
- nil
-
-coerceInt1(triple,t2) ==
- -- general interactive coercion
- -- the result is a new triple with type m2 or NIL (= failed)
- $useCoerceOrCroak: local := true
- t2 = $EmptyMode => NIL
- t1 := objMode triple
- t1=t2 => triple
- val := objVal triple
- absolutelyCanCoerceByCheating(t1,t2) => objNew(val,t2)
- isSubDomain(t2, t1) => coerceSubDomain(val, t1, t2)
-
- if typeIsASmallInteger(t1) then
- (t2 = $Integer) or typeIsASmallInteger(t2) => return objNew(val,t2)
- sintp := SINTP val
- sintp and (t2 = $PositiveInteger) and val > 0 => return objNew(val,t2)
- sintp and (t2 = $NonNegativeInteger) and val >= 0 => return objNew(val,t2)
-
- typeIsASmallInteger(t2) and isEqualOrSubDomain(t1, $Integer) and INTP val =>
- SINTP val => objNew(val,t2)
- NIL
-
- t2 = $Void => objNew(voidValue(),$Void)
- t2 = $Any => objNewWrap([t1,:unwrap val],'(Any))
-
- t1 = $Any and t2 ^= $OutputForm and ([t1',:val'] := unwrap val) and
- (ans := coerceInt(objNewWrap(val',t1'),t2)) => ans
-
- -- next is for tagged union selectors for the time being
- t1 is ['Variable,=t2] or t2 is ['Variable,=t1] => objNew(val,t2)
-
- STRINGP t2 =>
- t1 is ['Variable,v] and (t2 = PNAME(v)) => objNewWrap(t2,t2)
- val' := unwrap val
- (t2 = val') and ((val' = t1) or (t1 = $String)) => objNew(val,t2)
- NIL
- -- t1 is ['Tuple,S] and t2 ^= '(OutputForm) =>
- t1 is ['Tuple,S] =>
- coerceInt1(objNewWrap(asTupleAsList unwrap val, ['List, S]), t2)
- t1 is ['Union,:.] => coerceIntFromUnion(triple,t2)
- t2 is ['Union,:.] => coerceInt2Union(triple,t2)
- (STRINGP t1) and (t2 = $String) => objNew(val,$String)
- (STRINGP t1) and (t2 is ['Variable,v]) =>
- t1 = PNAME(v) => objNewWrap(v,t2)
- NIL
- (STRINGP t1) and (t1 = unwrap val) =>
- t2 = $OutputForm => objNew(t1,$OutputForm)
- NIL
- atom t1 => NIL
-
- if t1 = $AnonymousFunction and (t2 is ['Mapping,target,:margl]) then
- $useCoerceOrCroak := nil
- [.,vars,:body] := unwrap val
- vars :=
- atom vars => [vars]
- vars is ['Tuple,:.] => rest vars
- vars
- #margl ^= #vars => 'continue
- tree := mkAtree ['ADEF,vars,[target,:margl],[NIL for x in rest t2],:body]
- CATCH('coerceOrCroaker, bottomUp tree) = 'croaked => nil
- return getValue tree
-
- (t1 = $Symbol) and (t2 is ['Mapping,target,:margl]) =>
- null (mms := selectMms1(unwrap val,nil,margl,margl,target)) => NIL
- [dc,targ,:argl] := CAAR mms
- targ ^= target => NIL
- $genValue =>
- fun := getFunctionFromDomain(unwrap val,dc,argl)
- objNewWrap(fun,t2)
- val := NRTcompileEvalForm(unwrap val, CDR CAAR mms, evalDomain dc)
- objNew(val, t2)
- (t1 is ['Variable,sym]) and (t2 is ['Mapping,target,:margl]) =>
- null (mms := selectMms1(sym,target,margl,margl,NIL)) =>
- null (mms := selectMms1(sym,target,margl,margl,true)) => NIL
- [dc,targ,:argl] := CAAR mms
- targ ^= target => NIL
- dc is ["__FreeFunction__",:freeFun] => objNew( freeFun, t2 )
- $genValue => objNewWrap( getFunctionFromDomain(sym,dc,argl), t2 )
- val := NRTcompileEvalForm(sym, CDR CAAR mms, evalDomain dc)
- objNew(val, t2)
- (t1 is ['FunctionCalled,sym]) and (t2 is ['Mapping,target,:margl]) =>
- symNode := mkAtreeNode sym
- transferPropsToNode(sym,symNode)
- null (mms := selectLocalMms(symNode,sym,margl,target)) => NIL
- [dc,targ,:argl] := CAAR mms
- targ ^= target => NIL
- ml := [target,:margl]
- intName :=
- or/[mm for mm in mms | (mm is [[., :ml1],oldName,:.]
- and compareTypeLists(ml1,ml))] => [oldName]
- NIL
- null intName => NIL
- objNewWrap(intName,t2)
- (t1 is ['FunctionCalled,sym]) =>
- (t3 := get(sym,'mode,$e)) and t3 is ['Mapping,:.] =>
- (triple' := coerceInt(triple,t3)) => coerceInt(triple',t2)
- NIL
- NIL
-
- EQ(CAR(t1),'Variable) and PAIRP(t2) and
- (isEqualOrSubDomain(t2,$Integer) or
- (t2 = [$QuotientField, $Integer]) or MEMQ(CAR(t2),
- '(RationalNumber BigFloat NewFloat Float DoubleFloat))) => NIL
-
- ans := coerceRetract(triple,t2) or coerceIntTower(triple,t2) or
- [.,:arg]:= deconstructT t2
- arg and
- t:= coerceInt(triple,last arg)
- t and coerceByFunction(t,t2)
- ans or (isSubDomain(t1,$Integer) and
- coerceInt(objNew(val,$Integer),t2)) or
- coerceIntAlgebraicConstant(triple,t2) or
- coerceIntX(val,t1,t2)
-
-coerceSubDomain(val, tSuper, tSub) ==
- -- Try to coerce from a sub domain to a super domain
- val = '_$fromCoerceable_$ => nil
- super := GETDATABASE(first tSub, 'SUPERDOMAIN)
- superDomain := first super
- superDomain = tSuper =>
- coerceImmediateSubDomain(val, tSuper, tSub, CADR super)
- coerceSubDomain(val, tSuper, superDomain) =>
- coerceImmediateSubDomain(val, superDomain, tSub, CADR super)
- nil
-
-coerceImmediateSubDomain(val, tSuper, tSub, pred) ==
- predfn := getSubDomainPredicate(tSuper, tSub, pred)
- FUNCALL(predfn, val, nil) => objNew(val, tSub)
- nil
-
-getSubDomainPredicate(tSuper, tSub, pred) ==
- $env: local := $InteractiveFrame
- predfn := HGET($superHash, CONS(tSuper, tSub)) => predfn
- name := GENSYM()
- decl := ['_:, name, ['Mapping, $Boolean, tSuper]]
- interpret(decl, nil)
- arg := GENSYM()
- pred' := SUBST(arg, "#1", pred)
- defn := ['DEF, [name, arg], '(NIL NIL), '(NIL NIL), removeZeroOne pred']
- interpret(defn, nil)
- op := mkAtree name
- transferPropsToNode(name, op)
- predfn := CADAR selectLocalMms(op, name, [tSuper],$Boolean)
- HPUT($superHash, CONS(tSuper, tSub), predfn)
- predfn
-
-coerceIntX(val,t1, t2) ==
- -- some experimental things
- t1 = '(List (None)) =>
- -- this will almost always be an empty list
- null unwrap val =>
- -- try getting a better flavor of List
- null (t0 := underDomainOf(t2)) => NIL
- coerceInt(objNewWrap(val,['List,t0]),t2)
- NIL
- NIL
-
-compareTypeLists(tl1,tl2) ==
- -- returns true if every type in tl1 is = or is a subdomain of
- -- the corresponding type in tl2
- for t1 in tl1 for t2 in tl2 repeat
- null isEqualOrSubDomain(t1,t2) => return NIL
- true
-
-coerceIntAlgebraicConstant(object,t2) ==
- -- should use = from domain, but have to check on defaults code
- t1 := objMode object
- val := objValUnwrap object
- ofCategory(t1,'(Monoid)) and ofCategory(t2,'(Monoid)) and
- val = getConstantFromDomain('(One),t1) =>
- objNewWrap(getConstantFromDomain('(One),t2),t2)
- ofCategory(t1,'(AbelianMonoid)) and ofCategory(t2,'(AbelianMonoid)) and
- val = getConstantFromDomain('(Zero),t1) =>
- objNewWrap(getConstantFromDomain('(Zero),t2),t2)
- NIL
-
-coerceUnion2Branch(object) ==
- [.,:unionDoms] := objMode object
- doms := orderUnionEntries unionDoms
- predList:= mkPredList doms
- doms := stripUnionTags doms
- val' := objValUnwrap object
- predicate := NIL
- targetType:= NIL
- for typ in doms for pred in predList while ^targetType repeat
- evalSharpOne(pred,val') =>
- predicate := pred
- targetType := typ
- null targetType => keyedSystemError("S2IC0013",NIL)
- predicate is ['EQCAR,.,p] => objNewWrap(CDR val',targetType)
- objNew(objVal object,targetType)
-
-coerceBranch2Union(object,union) ==
- -- assumes type is a member of unionDoms
- unionDoms := CDR union
- doms := orderUnionEntries unionDoms
- predList:= mkPredList doms
- doms := stripUnionTags doms
- p := position(objMode object,doms)
- p = -1 => keyedSystemError("S2IC0014",[objMode object,union])
- val := objVal object
- predList.p is ['EQCAR,.,tag] =>
- objNewWrap([removeQuote tag,:unwrap val],union)
- objNew(val,union)
-
-coerceInt2Union(object,union) ==
- -- coerces to a Union type, adding numeric tags
- -- first cut
- unionDoms := stripUnionTags CDR union
- t1 := objMode object
- member(t1,unionDoms) => coerceBranch2Union(object,union)
- val := objVal object
- val' := unwrap val
- (t1 = $String) and member(val',unionDoms) =>
- coerceBranch2Union(objNew(val,val'),union)
- noCoerce := true
- val' := nil
- for d in unionDoms while noCoerce repeat
- (val' := coerceInt(object,d)) => noCoerce := nil
- val' => coerceBranch2Union(val',union)
- NIL
-
-coerceIntFromUnion(object,t2) ==
- -- coerces from a Union type to something else
- coerceInt(coerceUnion2Branch object,t2)
-
-coerceIntByMap(triple,t2) ==
- -- idea is this: if t1 is D U1 and t2 is D U2, then look for
- -- map: (U1 -> U2, D U1) -> D U2. If it exists, then create a
- -- function to do the coercion on the element level and call the
- -- map function.
- t1 := objMode triple
- t2 = t1 => triple
- u2 := deconstructT t2 -- compute t2 first because of Expression
- 1 = #u2 => NIL -- no under domain
- u1 := deconstructT t1
- 1 = #u1 => NIL
- CAAR u1 ^= CAAR u2 => nil -- constructors not equal
- ^valueArgsEqual?(t1, t2) => NIL
--- CAR u1 ^= CAR u2 => NIL
- top := CAAR u1
- u1 := underDomainOf t1
- u2 := underDomainOf t2
-
- -- handle a couple of special cases for subdomains of Integer
- top in '(List Vector Segment Stream UniversalSegment Array)
- and isSubDomain(u1,u2) => objNew(objVal triple, t2)
-
- args := [['Mapping,u2,u1],t1]
- if $reportBottomUpFlag then
- sayFunctionSelection('map,args,t2,NIL,
- '"coercion facility (map)")
- mms := selectMms1('map,t2,args,args,NIL)
- if $reportBottomUpFlag then
- sayFunctionSelectionResult('map,args,mms)
- null mms => NIL
-
- [[dc,:sig],slot,.]:= CAR mms
- fun := compiledLookup('map,sig,evalDomain(dc))
- NULL fun => NIL
- [fn,:d]:= fun
- fn = function Undef => NIL
- -- now compile a function to do the coercion
- code := ['SPADCALL,['CONS,["function","coerceIntByMapInner"],MKQ [u1,:u2]],
- wrapped2Quote objVal triple,MKQ fun]
- -- and apply the function
- val := CATCH('coerceFailure,timedEvaluate code)
- (val = $coerceFailure) => NIL
- objNewWrap(val,t2)
-
-coerceIntByMapInner(arg,[u1,:u2]) == coerceOrThrowFailure(arg,u1,u2)
--- [u1,:u2] gets passed as the "environment", which is why we have this
--- slightly clumsy locution JHD 31.July,1990
-
-valueArgsEqual?(t1, t2) ==
- -- returns true if the object-valued arguments to t1 and t2 are the same
- -- under coercion
- coSig := CDR GETDATABASE(CAR t1, 'COSIG)
- constrSig := CDR getConstructorSignature CAR t1
- tl1 := replaceSharps(constrSig, t1)
- tl2 := replaceSharps(constrSig, t2)
- not MEMQ(NIL, coSig) => true
- done := false
- value := true
- for a1 in CDR t1 for a2 in CDR t2 for cs in coSig
- for m1 in tl1 for m2 in tl2 while not done repeat
- ^cs =>
- trip := objNewWrap(a1, m1)
- newVal := coerceInt(trip, m2)
- null newVal => (done := true; value := false)
- ^algEqual(a2, objValUnwrap newVal, m2) =>
- (done := true; value := false)
- value
-
-coerceIntTower(triple,t2) ==
- -- tries to find a coercion from top level t2 to somewhere inside t1
- -- builds new argument type, for which coercion is called recursively
- x := coerceIntByMap(triple,t2) => x
- x := coerceIntCommute(triple,t2) => x
- x := coerceIntPermute(triple,t2) => x
- x := coerceIntSpecial(triple,t2) => x
- x := coerceIntTableOrFunction(triple,t2) => x
- t1 := objMode triple
- [c1,:arg1]:= deconstructT t1
- arg1 and
- TL:= NIL
- arg:= arg1
- until x or not arg repeat
- t:= last arg
- [c,:arg]:= deconstructT t
- TL:= [c,arg,:TL]
- x := arg and coerceIntTest(t,t2) =>
- CDDR TL =>
- s := constructT(c1,replaceLast(arg1,bubbleConstructor TL))
- (null isValidType(s)) => (x := NIL)
- x := (coerceIntByMap(triple,s) or
- coerceIntTableOrFunction(triple,s)) =>
- [c2,:arg2]:= deconstructT last s
- s:= bubbleConstructor [c2,arg2,c1,arg1]
- (null isValidType(s)) => (x := NIL)
- x:= coerceIntCommute(x,s) =>
- x := (coerceIntByMap(x,t2) or
- coerceIntTableOrFunction(x,t2))
- s:= bubbleConstructor [c,arg,c1,arg1]
- (null isValidType(s)) => (x := NIL)
- x:= coerceIntCommute(triple,s) =>
- x:= (coerceIntByMap(x,t2) or
- coerceIntTableOrFunction(x,t2))
- x
-
-coerceIntSpecial(triple,t2) ==
- t1 := objMode triple
- t2 is ['SimpleAlgebraicExtension,R,U,.] and t1 = R =>
- null (x := coerceInt(triple,U)) => NIL
- coerceInt(x,t2)
- NIL
-
-coerceIntTableOrFunction(triple,t2) ==
- -- this function does the actual coercion to t2, but not to an
- -- argument type of t2
- null isValidType t2 => NIL -- added 9-18-85 by RSS
- null isLegitimateMode(t2,NIL,NIL) => NIL -- added 6-28-87 by RSS
- t1 := objMode triple
- p:= ASSQ(CAR t1,$CoerceTable)
- p and ASSQ(CAR t2,CDR p) is [.,:[tag,fun]] =>
- val := objVal triple
- fun='Identity => objNew(val,t2)
- tag='total =>
- coerceByTable(fun,val,t1,t2,'T) or coerceByFunction(triple,t2)
- coerceByTable(fun,val,t1,t2,NIL) or coerceByFunction(triple,t2)
- coerceByFunction(triple,t2)
-
-coerceCommuteTest(t1,t2) ==
- null isLegitimateMode(t2,NIL,NIL) => NIL
-
- -- sees whether t1 = D1 D2 R and t2 = D2 D1 S
- null (u1 := underDomainOf t1) => NIL
- null (u2 := underDomainOf t2) => NIL
-
- -- must have underdomains (ie, R and S must be there)
-
- null (v1 := underDomainOf u1) => NIL
- null (v2 := underDomainOf u2) => NIL
-
- -- now check that cross of constructors is correct
- (CAR(deconstructT t1) = CAR(deconstructT u2)) and
- (CAR(deconstructT t2) = CAR(deconstructT u1))
-
-coerceIntCommute(obj,target) ==
- -- note that the value in obj may be $fromCoerceable$, for canCoerce
- source := objMode obj
- null coerceCommuteTest(source,target) => NIL
- S := underDomainOf source
- T := underDomainOf target
- source = T => NIL -- handle in other ways
-
- source is [D,:.] =>
- fun := GETL(D,'coerceCommute) or
- INTERN STRCONC('"commute",STRINGIMAGE D)
- functionp fun =>
- PUT(D,'coerceCommute,fun)
- u := objValUnwrap obj
- c := CATCH('coerceFailure,FUNCALL(fun,u,source,S,target,T))
- (c = $coerceFailure) => NIL
- u = "$fromCoerceable$" => c
- objNewWrap(c,target)
- NIL
- NIL
-
-coerceIntPermute(object,t2) ==
- t2 in '((Integer) (OutputForm)) => NIL
- t1 := objMode object
- towers := computeTTTranspositions(t1,t2)
- -- at this point, CAR towers = t1 and last towers should be similar
- -- to t2 in the sense that the components of t1 are in the same order
- -- as in t2. If length towers = 2 and t2 = last towers, we quit to
- -- avoid an infinte loop.
- NULL towers or NULL CDR towers => NIL
- NULL CDDR towers and t2 = CADR towers => NIL
- -- do the coercions successively, quitting if any fail
- ok := true
- for t in CDR towers while ok repeat
- null (object := coerceInt(object,t)) => ok := NIL
- ok => object
- NIL
-
-computeTTTranspositions(t1,t2) ==
- -- decompose t1 into its tower parts
- tl1 := decomposeTypeIntoTower t1
- tl2 := decomposeTypeIntoTower t2
- -- if not at least 2 parts, don't bother working here
- null (rest tl1 and rest tl2) => NIL
- -- determine the relative order of the parts of t1 in t2
- p2 := [position(d1,tl2) for d1 in tl1]
- member(-1,p2) => NIL -- something not present
- -- if they are all ascending, this function will do nothing
- p2' := MSORT p2
- p2 = p2' => NIL
- -- if anything is repeated twice, leave
- p2' ^= MSORT REMDUP p2' => NIL
- -- create a list of permutations that transform the tower parts
- -- of t1 into the order they are in in t2
- n1 := #tl1
- p2 := LIST2VEC compress(p2,0,# REMDUP tl1) where
- compress(l,start,len) ==
- start >= len => l
- member(start,l) => compress(l,start+1,len)
- compress([(i < start => i; i - 1) for i in l],start,len)
- -- p2 now has the same position numbers as p1, we need to determine
- -- a list of permutations that takes p1 into p2.
- -- them
- perms := permuteToOrder(p2,n1-1,0)
- towers := [tl1]
- tower := LIST2VEC tl1
- for perm in perms repeat
- t := tower.(CAR perm)
- tower.(CAR perm) := tower.(CDR perm)
- tower.(CDR perm) := t
- towers := CONS(VEC2LIST tower,towers)
- towers := [reassembleTowerIntoType tower for tower in towers]
- if CAR(towers) ^= t2 then towers := cons(t2,towers)
- NREVERSE towers
-
-decomposeTypeIntoTower t ==
- ATOM t => [t]
- d := deconstructT t
- NULL rest d => [t]
- rd := REVERSE t
- [reverse QCDR rd,:decomposeTypeIntoTower QCAR rd]
-
-reassembleTowerIntoType tower ==
- ATOM tower => tower
- NULL rest tower => CAR tower
- [:top,t,s] := tower
- reassembleTowerIntoType [:top,[:t,s]]
-
-permuteToOrder(p,n,start) ==
- -- p is a vector of the numbers 0..n. This function returns a list
- -- of swaps of adjacent elements so that p will be in order. We only
- -- begin looking at index start
- r := n - start
- r <= 0 => NIL
- r = 1 =>
- p.r < p.(r+1) => NIL
- [[r,:(r+1)]]
- p.start = start => permuteToOrder(p,n,start+1)
- -- bubble up element start to the top. Find out where it is
- stpos := NIL
- for i in start+1..n while not stpos repeat
- if p.i = start then stpos := i
- perms := NIL
- while stpos ^= start repeat
- x := stpos - 1
- perms := [[x,:stpos],:perms]
- t := p.stpos
- p.stpos := p.x
- p.x := t
- stpos := x
- APPEND(NREVERSE perms,permuteToOrder(p,n,start+1))
-
-coerceIntTest(t1,t2) ==
- -- looks whether there exists a table entry or a coercion function
- -- thus the type can be bubbled before coerceIntTableOrFunction is called
- t1=t2 or
- b:=
- p:= ASSQ(CAR t1,$CoerceTable)
- p and ASSQ(CAR t2,CDR p)
- b or coerceConvertMmSelection('coerce,t1,t2) or
- ($useConvertForCoercions and
- coerceConvertMmSelection('convert,t1,t2))
-
-coerceByTable(fn,x,t1,t2,isTotalCoerce) ==
- -- catch point for 'failure in boot coercions
- t2 = $OutputForm and ^(newType? t1) => NIL
- isWrapped x =>
- x:= unwrap x
- c:= CATCH('coerceFailure,FUNCALL(fn,x,t1,t2))
- c=$coerceFailure => NIL
- objNewWrap(c,t2)
- isTotalCoerce => objNew([fn,x,MKQ t1,MKQ t2],t2)
- objNew(['catchCoerceFailure,MKQ fn,x,MKQ t1,MKQ t2],t2)
-
-catchCoerceFailure(fn,x,t1,t2) ==
- -- compiles a catchpoint for compiling boot coercions
- c:= CATCH('coerceFailure,FUNCALL(fn,x,t1,t2))
- c = $coerceFailure =>
- throwKeyedMsgCannotCoerceWithValue(wrap unwrap x,t1,t2)
- c
-
-coercionFailure() ==
- -- does the throw on coercion failure
- THROW('coerceFailure,$coerceFailure)
-
-coerceByFunction(T,m2) ==
- -- using the new modemap selection without coercions
- -- should not be called by canCoerceFrom
- x := objVal T
- x = '_$fromCoerceable_$ => NIL
- m2 is ['Union,:.] => NIL
- m1 := objMode T
- m2 is ['Boolean,:.] and m1 is ['Equation,ud] =>
- dcVector := evalDomain ud
- fun :=
- isWrapped x =>
- NRTcompiledLookup("=", [$Boolean, '$, '$], dcVector)
- NRTcompileEvalForm("=", [$Boolean, '$, '$], dcVector)
- [fn,:d]:= fun
- isWrapped x =>
- x:= unwrap x
- objNewWrap(SPADCALL(CAR x,CDR x,fun),m2)
- x isnt ['SPADCALL,a,b,:.] => keyedSystemError("S2IC0015",NIL)
- code := ['SPADCALL, a, b, fun]
- objNew(code,$Boolean)
- -- If more than one function is found, any should suffice, I think -scm
- if not (mm := coerceConvertMmSelection(funName := 'coerce,m1,m2)) then
- mm := coerceConvertMmSelection(funName := 'convert,m1,m2)
- mm =>
- [[dc,tar,:args],slot,.]:= mm
- dcVector := evalDomain(dc)
- fun:=
---+
- isWrapped x =>
- NRTcompiledLookup(funName,slot,dcVector)
- NRTcompileEvalForm(funName,slot,dcVector)
- [fn,:d]:= fun
- fn = function Undef => NIL
- isWrapped x =>
---+
- $: fluid := dcVector
- val := CATCH('coerceFailure, SPADCALL(unwrap x,fun))
- (val = $coerceFailure) => NIL
- objNewWrap(val,m2)
- env := fun
- code := ['failCheck, ['SPADCALL, x, env]]
--- tar is ['Union,:.] => objNew(['failCheck,code],m2)
- objNew(code,m2)
- -- try going back to types like RN instead of QF I
- m1' := eqType m1
- m2' := eqType m2
- (m1 ^= m1') or (m2 ^= m2') => coerceByFunction(objNew(x,m1'),m2')
- NIL
-
-hasCorrectTarget(m,sig is [dc,tar,:.]) ==
- -- tests whether the target of signature sig is either m or a union
- -- containing m. It also discards TEQ as it is not meant to be
- -- used at top-level
- dc is ['TypeEquivalence,:.] => NIL
- m=tar => 'T
- tar is ['Union,t,'failed] => t=m
- tar is ['Union,'failed,t] and t=m
-
-@
-\eject
-\begin{thebibliography}{99}
-\bibitem{1} nothing
-\end{thebibliography}
-\end{document}