\documentclass{article}
\usepackage{axiom}
\begin{document}
\title{\$SPAD/src/algebra any.spad}
\author{Robert S. Sutor}
\maketitle
\begin{abstract}
\end{abstract}
\eject
\tableofcontents
\eject
\section{domain NONE None}
<<domain NONE None>>=
)abbrev domain NONE None
++ Author:
++ Date Created:
++ Change History:
++ Basic Functions: coerce
++ Related Constructors: NoneFunctions1
++ Also See: Any
++ AMS Classification:
++ Keywords: none, empty
++ Description:
++    \spadtype{None} implements a type with no objects. It is mainly
++    used in technical situations where such a thing is needed (e.g.
++    the interpreter and some of the internal \spadtype{Expression}
++    code).

None():SetCategory == add
    coerce(none:%):OutputForm == "NONE" :: OutputForm
    x:% = y:% == EQ(x,y)$Lisp

@
\section{package NONE1 NoneFunctions1}
<<package NONE1 NoneFunctions1>>=
)abbrev package NONE1 NoneFunctions1
++ Author:
++ Date Created:
++ Change History:
++ Basic Functions: coerce
++ Related Constructors: None
++ Also See:
++ AMS Classification:
++ Keywords:
++ Description:
++   \spadtype{NoneFunctions1} implements functions on \spadtype{None}.
++   It particular it includes a particulary dangerous coercion from
++   any other type to \spadtype{None}.

NoneFunctions1(S:Type): Exports == Implementation where
  Exports ==> with
    coerce: S -> None
      ++ coerce(x) changes \spad{x} into an object of type
      ++ \spadtype{None}.

  Implementation ==> add
    coerce(s:S):None == s pretend None

@
\section{domain ANY Any}
<<domain ANY Any>>=
)abbrev domain ANY Any
++ Author: Robert S. Sutor
++ Date Created:
++ Change History:
++ Basic Functions: any, domainOf, objectOf, dom, obj, showTypeInOutput
++ Related Constructors: AnyFunctions1
++ Also See: None
++ AMS Classification:
++ Keywords:
++ Description:
++   \spadtype{Any} implements a type that packages up objects and their
++   types in objects of \spadtype{Any}. Roughly speaking that means
++   that if \spad{s : S} then when converted to \spadtype{Any}, the new
++   object will include both the original object and its type. This is
++   a way of converting arbitrary objects into a single type without
++   losing any of the original information. Any object can be converted
++   to one of \spadtype{Any}.

Any(): SetCategory with
        any             : (SExpression, None) -> %
          ++ any(type,object) is a technical function for creating
          ++ an object of \spadtype{Any}. Arugment \spad{type} is a \spadgloss{LISP} form
          ++ for the type of \spad{object}.
        domainOf        : % -> OutputForm
          ++ domainOf(a) returns a printable form of the type of the
          ++ original object that was converted to \spadtype{Any}.
        objectOf        : % -> OutputForm
          ++ objectOf(a) returns a printable form of the
          ++ original object that was converted to \spadtype{Any}.
        dom             : % -> SExpression
          ++ dom(a) returns a \spadgloss{LISP} form of the type of the
          ++ original object that was converted to \spadtype{Any}.
        obj             : % -> None
          ++ obj(a) essentially returns the original object that was
          ++ converted to \spadtype{Any} except that the type is forced
          ++ to be \spadtype{None}.
        showTypeInOutput: Boolean -> String
          ++ showTypeInOutput(bool) affects the way objects of
          ++ \spadtype{Any} are displayed. If \spad{bool} is true
          ++ then the type of the original object that was converted
          ++ to \spadtype{Any} will be printed. If \spad{bool} is
          ++ false, it will not be printed.

 == add
     Rep := Record(dm: SExpression, ob: None)

     printTypeInOutputP:Reference(Boolean) := ref false

     obj x      == x.ob
     dom x      == x.dm
     domainOf x == x.dm pretend OutputForm
     x = y      ==
         dx := dom x
         dy := dom y
         dx ~= dy => false
         Dx : Type := evalType(dx)$Lisp
         Dx has BasicType =>
             (obj x) pretend Dx = (obj y) pretend Dx
         -- FIXME: we want
         -- error "Comparison in domain which is not a BasicType"
         -- but currently pattern matching needs
         EQ(obj x, obj y)$Lisp

     objectOf(x : %) : OutputForm ==
       spad2BootCoerce(x.ob, x.dm,
          list('OutputForm)$List(Symbol))$Lisp

     showTypeInOutput(b : Boolean) : String ==
      printTypeInOutputP := ref b
      b=> "Type of object will be displayed in output of a member of Any"
      "Type of object will not be displayed in output of a member of Any"

     coerce(x):OutputForm ==
       obj1 : OutputForm := objectOf x
       not deref printTypeInOutputP => obj1
       dom1 :=
         p:Symbol := prefix2String(devaluate(x.dm)$Lisp)$Lisp
         atom?(p pretend SExpression) => list(p)$List(Symbol)
         list(p)$Symbol
       hconcat cons(obj1,
         cons(":"::OutputForm, [a::OutputForm for a in dom1]))

     any(domain, object) ==
       (isValidType(domain)$Lisp)@Boolean => [domain, object]
       domain := devaluate(domain)$Lisp
       (isValidType(domain)$Lisp)@Boolean => [domain, object]
       error "function any must have a domain as first argument"

@
\section{package ANY1 AnyFunctions1}
<<package ANY1 AnyFunctions1>>=
)abbrev package ANY1 AnyFunctions1
++ Author:
++ Date Created:
++ Change History:
++ Basic Functions:  coerce, retractIfCan, retractable?, retract
++ Related Constructors: Any
++ Also See:
++ AMS Classification:
++ Keywords:
++ Description:
++   \spadtype{AnyFunctions1} implements several utility functions for
++   working with \spadtype{Any}. These functions are used to go back
++   and forth between objects of \spadtype{Any} and objects of other
++   types.

AnyFunctions1(S:Type): with
        coerce      : S -> Any
          ++ coerce(s) creates an object of \spadtype{Any} from the
          ++ object \spad{s} of type \spad{S}.
        retractIfCan: Any -> Union(S, "failed")
          ++ retractIfCan(a) tries change \spad{a} into an object
          ++ of type \spad{S}. If it can, then such an object is
          ++ returned. Otherwise, "failed" is returned.
        retractable?: Any -> Boolean
          ++ retractable?(a) tests if \spad{a} can be converted
          ++ into an object of type \spad{S}.
        retract     : Any -> S
          ++ retract(a) tries to convert \spad{a} into an object of
          ++ type \spad{S}. If possible, it returns the object.
          ++ Error: if no such retraction is possible.

    == add
        import NoneFunctions1(S)

        Sexpr:SExpression := devaluate(S)$Lisp

        retractable? a  == dom(a) = Sexpr
        coerce(s:S):Any == any(Sexpr, s::None)

        retractIfCan a ==
            retractable? a => obj(a) pretend S
            "failed"

        retract a ==
            retractable? a => obj(a) pretend S
            error "Cannot retract value."

@
\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>>

-- Any and None complete the type lattice. They are also used in the
-- interpreter in various situations. For example, it is always possible
-- to resolve two types in the interpreter because at worst the answer
-- may be Any.

<<domain NONE None>>
<<package NONE1 NoneFunctions1>>
<<domain ANY Any>>
<<package ANY1 AnyFunctions1>>
@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}
