
/* typec.q: Various useful type-checking predicates.
   $Id: typec.q,v 1.17 2006/06/26 06:22:41 agraef Exp $ */

/* This file is part of the Q programming system.

   The Q programming system is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   The Q programming system is distributed in the hope that it will be
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

/* Syntactic type-checking. These predicates just check whether an object
   (which may be of any type) is of the appropriate type. They are all
   equivalent to the corresponding type guard. */

public isbool X;	// truth values
public ischar X;	// characters
public isexcept X;	// exceptions
public isfile X;	// files
public isfunction X;	// lambda functions
public islist X;	// lists
public isstr X;		// strings
public istuple X;	// tuples

/* Syntactic predicates for the number types. For convenience, the predicates
   for the Complex and Rational types (cf. complex.q and rational.q) are also
   defined here. */

public isint X;		// integers
public isrational X;	// rational numbers
public isfloat X;	// floating point numbers
public isreal X;	// real numbers
public iscomplex X;	// complex numbers
public isnum X;		// all numbers

/* Semantic type-checking for numbers. In difference to the syntactic
   predicates above, these functions classify numbers according to the kind of
   abstract mathematical object they represent, regardless of the concrete
   representation. */

public isintval X;	// integer value
public isratval X;	// rational value
public isrealval X;	// real value
public iscompval X;	// complex value

/* Check for exactness (generally, any numeric value not involving floating
   point numbers is considered exact). */

public isexact X;	// number with exact representation
public isinexact X;	// number with inexact representation

/* Check for infinities and NaNs (IEEE floating point numbers). */

public isinf X;		// infinite number
public isnan X;		// not a number

/* Specialized predicates for dealing with symbols, closures and enumeration
   types. */

public special issym X;	// function and variable symbols
public isenum X;	// enumeration type member

/* Implementation. ***********************************************************/

isbool _:Bool		= true;
isbool _		= false otherwise;

ischar _:Char		= true;
ischar _		= false otherwise;

isexcept _:Exception	= true;
isexcept _		= false otherwise;

isfile _:File		= true;
isfile _		= false otherwise;

isfunction _:Function	= true;
isfunction _		= false otherwise;

islist _:List		= true;
islist _		= false otherwise;

isstr _:String		= true;
isstr _			= false otherwise;

istuple _:Tuple		= true;
istuple _		= false otherwise;

/* Syntactic number predicates. */

import rational, complex;

isint _:Int		= true;
isint _			= false otherwise;

isrational _:Rational	= true;
isrational _		= false otherwise;

isfloat _:Float		= true;
isfloat _		= false otherwise;

isreal _:Real		= true;
isreal _		= false otherwise;

iscomplex _:Complex	= true;
iscomplex _		= false otherwise;

isnum _:Num		= true;
isnum _			= false otherwise;

/* Semantic number predicates. */

isintval _:Int		= true;
isintval X:Rational	= (D=1) where (_:Int,D:Int) = num_den X;
isintval X:Float	= not isinf X and then (frac X=0.0);
isintval X:Complex	= iscompval X and then (im X=0)
			  and then isexact (im X) and then
			  isintval (re X);

isratval _:Int		= true;
isratval X:Rational	= D<>0 where (_:Int,D:Int) = num_den X;
isratval X:Float	= not isinf X and then not isnan X;
isratval X:Complex	= iscompval X and then (im X=0)
			  and then isexact (im X) and then
			  isratval (re X);

isrealval _:Int		= true;
isrealval X:Rational	= D<>0 where (_:Int,D:Int) = num_den X;
isrealval _:Float	= true;
isrealval X:Complex	= iscompval X and then (im X=0)
			  and then isexact (im X);

iscompval X:Complex	= isrealval (re X) and then isrealval (im X);
iscompval X:Num		= true if isrealval X;

isexact _:Int		= true;
isexact X:Rational	= isratval X;
isexact X:Complex	= isexact (re X) and then isexact (im X);

isinexact _:Float	= true;
isinexact X:Complex	= isinexact (re X) or else isinexact (im X);

isinf X:Float		= not isnan X and then isnan (X-X);
isnan X:Float		= eq X nan;

/* Default rules at lowest priority. This gives programmers the opportunity to
   extend the predicates above if an application needs to extend the numeric
   tower. */

@-0x80000000
isintval _		= false otherwise;
isratval _		= false otherwise;
isrealval _		= false otherwise;
iscompval _		= false otherwise;
isexact _		= false otherwise;
isinexact _		= false otherwise;
isinf _			= false otherwise;
isnan _			= false otherwise;
@0

/* Special-purpose predicates. */

issym X			= isfun X or else isvar X;

// This is not 100% foolproof but should work in most cases.
isenum X		= isconst X and then isint (ord X);
