-- «•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•»«•» -- Making the license a package comment causes it to be part of every -- runnable frege code. {-- Copyright © 2011, Ingo Wechsung 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 copyright holder 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 HOLDER 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.* -} {-- * * This package provides basic definitions for the Frege language. * * The _Prelude_ packages are imported explicitly or implicetly during compilation * of any other package. * They define basic data structures, classes and functions. * * The types and constructors for lists, unit type and tuple types are not * defined here: They are provided programmaticaly by the compiler when it * compiles a package with the name @frege.prelude.PreludeBase@. Nevertheless, they are * considered part of the _Prelude_, thus qualified names like '(,)' * are okay. * * The packages are _implementation specific_ insofar as the compiler may * assume that certain items are defined here in a certain way. * Changes may thus lead * to compiler crashes or java code that will be rejected by the java compiler. -} {- Overview of the type class hierarchy > Eq equality, provides relational operators '==' and '!=' > Ord ordering, provides relational operators '<' '<=' '>' '>=' and '<=>' > Enum enumarations (succ, pred, etc.) > Num numbers > Real real numbers > Integral integral numbers > Show string representation of values > Length data types that have a length > Empty data types that have an empty value > AbstractList data types that behave like lists -} {- Uncommon characters defined here: > Char used for howto type in editor > • function composition ALT+0149 CTRL+. > « left shift? ALT+0171 CTRL+< > » right shift? ALT+0187 CTRL+Shift+< > ¦ to be determined ALT+0166 Alt+Shift+< > ¿ to be determined ALT+0191 CTRL+ß (?) > ´ regular expressions ALT+0180 > -} protected package frege.prelude.PreludeBase inline candidates (otherwise, id, const, asTypeOf, $!, $, •, <~, flip, ST.>>=, State.put, State.change, State.>>=, State.>>, State.return, State.run) where {- * $Author$ * $Revision$ * $Id$ * $Date$ -} {- * Here are the standard operators in precedence order * (higher numbers mean more tight binding) * This is so that @!x@ can be thought of having * precedence 18 and @(f x)@ can be tought of as having precedence 17 -} infixr 16 `<~` `•` -- a <~ (b <~ c) == (c ~> b) ~> a infixl 16 `!!` `~>` infixr 15 `**` `??` -- `^` infix 15 `=~` `!~` `?~` `/~` `~` `~~` `~~~` infixl 14 `*` `/` `%` `mod` `rem` `div` `quot` infix 14 `\\` infixl 13 `+` -- `-` is handled specially infixr 13 `++` mplus infixl 12 `<<` `bshl` `bshr` `ushr` infixl 11 `band` infixl 10 `bor` `bxor` infix 9 `<=` `>=` `<` `>` `elem` `notElem` infix 8 `<=>` `compare` infix 7 `==` `!=` `/=` `===` `!==` -- `<>` infixr 6 `&&` `und` infixr 5 `||` `oder` `^^` infix 4 `..` infixr 4 `:` infixl 4 `<$>` `<*>` `<*` `*>` fmap infixl 3 `>>` `>>=` -- monad bind infixr 3 `<=<` `>=>` -- Kleisli opeartors infixr 2 `:=` `=<<` `@` `seq` -- so that in x@a:bs x is bound to the list infixr 1 `$` `$!` -------------------------------------------------------------------------------- -- CLASS SECTION -------------------------------------------------------------------------------- {-- The class 'Eq' provides operators '==', '!=' and 'hashCode'. All types whose values can be compared for equality should be instances of this class. For algebraic data types instances can be automatically derived if all components are themselves instances of 'Eq'. -} class Eq eq where --- Check for equality. This function is required in all instances. --- Ayn Rand's favorite law --- > a == a --- shall be obeyed by all implementations. (==), (/=) :: eq -> eq -> Bool -- must be defined in instances --- Check for inequality. The default implementation obeys the laws --- > !(a != a) --- > (a != b) == !(a == b) --- > (a == b) != (a != b) --- These laws shall also be obeyed in all implementations. (!=) :: eq -> eq -> Bool a!=b = if a==b then false else true -- may be replaced by more efficient version --- provided for Haskell compatibility as an alias for '!=' (/=) = (!=) --- Compute a hash code. --- The follwoing rules shall hold in all instances: --- > a == b ==> hashCode a == hashCode b --- > hashCode a != hashCode b ==> a != b --- In addition, unequal values should produce unequal hashcodes more likely than not. hashCode :: eq -> Int instance Eq Bool where pure native == :: Bool -> Bool -> Bool pure native != :: Bool -> Bool -> Bool hashCode true = 1 hashCode false = 0 {-- * Determines the constructor of a value. * This is used like * >constructor arg * where @arg@ is any frege value. * * Returns 0 for product types and native types or * the /constructor number/ for constructed types. The /constructor number/ * is a small integer stored in every constructed value. It indicates by * what data constructor a value was constructed. * * The compiler assigns constructor numbers starting from 0 to the constructors * defined in a @data@ definition in the order of their appearance. * * Examples * >constructor [] == 0 * >constructor (a:as) == 1 * >constructor "string" == 0 // native value * * This function is strict in its argument, i.e. * >constructor undefined == undefined * * *Implementation specific:* This function is used in derived instances * of 'Eq' and 'Ord'. -} pure native constructor "frege.RT.constructor" :: a -> Int; -- ######## Java Boxed Types #################### -- data JBoolean = native java.lang.Boolean -- data JByte = native java.lang.Byte -- data JChar = native java.lang.Character -- data JShort = native java.lang.Short -- data JInteger = native java.lang.Integer -- data JLong = native java.lang.Long -- data JFloat = native java.lang.Float -- data JDouble = native java.lang.Double --######### Basic types #################### {-- 'Bool' values are based on Java's primitive @boolean@ values. Note that @true@ and @false@ are literals, not constructors. -} data Bool = native boolean {-- This is a constant with the value @true@. It is most often used as the last alternative in pattern guards: > foo n | n >= 0 = ... > | otherwise = ... -} otherwise = true {-- This is used by code generation when a conditional expression appears in a lazy context, i.e. > (42, if foo then bar else baz) @lazyif a b c@ evaluates to @b@ if @a@ is @true@, otherwise to @c@. -} lazyif a b c = if a then b else c {-- 'Int' values are based on Java's primitive @int@ values. The existence of this type is assumed in numerous places in the compiler. Like with all @native@ Java types, be they primitive or reference types, Frege holds the raw @int@ in boxed form. However, in certain cases the compiler will optimize the boxing away: - Strict variables or function arguments work with the unboxed value directly. - Functions with a @native@ return type generally return the unboxed value. Polymorphic data structures or functions always work with boxed values. Thus, for example, the function > sum a b c = a + b + c can compute the sum of 3 'Int's, 'Long's, 'Double's or any other values of a type that is an instance of type class 'Num', but it may be somewhat slower than functions spezialized for a given type. According to the Java Language Specification, @int@ values are 32 bit wide signed two's complement integers (§4.2). Java operations on @int@ do not indicate overflow or underflow in any way (§4.2.2). Instead, just the low 32 bits of every result are retained. -} data Int = native int where --- convert an 'Int' to a 'Float', i.e. @2.float == 2.0f@. --- For large integers, the result may have been be rounded. pure native float java.lang.Float.valueOf :: Int -> Float --- convert an 'Int' to a 'Double', i.e. @2.double == 2.0@. pure native double java.lang.Double.valueOf :: Int -> Double --- Convert an 'Int' to a 'Long', i.e. @2.long == 2L@. pure native long java.lang.Long.valueOf :: Int -> Long --- @i.char@ returns the 'Char' value whose ordinal number is @i@ --- Result is only valid for integers in the range 0..65535 pure native char "(char)" :: Int -> Char --- Computes binary /or/ of two integers. Uses the java @|@-operator. pure native bor "|" :: Int -> Int -> Int --- Computes binary /exclusive or/ of two integers. Uses the java @^@-operator. pure native bxor "^" :: Int -> Int -> Int --- Computes binary /and/ of two integers. Uses the java @&@-operator. pure native band "&" :: Int -> Int -> Int -- Compare 2 intergers, use java operator -- pure native (==) :: Int -> Int -> Bool // is defined in Eq --- convert to a hexadecimal string pure native toHexString java.lang.Integer.toHexString :: Int -> String --- The 'hashCode' of an 'Int' is the identity hashCode i = i {-- * 'Integer' is * a type for integer numbers of unlimited size, * It has instances for 'Eq', 'Ord', 'Show' and 'Integral'. * This is derived from @java.math.BigInteger@. -} data Integer = native java.math.BigInteger where -- constants pure native zero java.math.BigInteger.ZERO :: Integer pure native one java.math.BigInteger.ONE :: Integer pure native ten java.math.BigInteger.TEN :: Integer --- construction from a 'Long', see also 'String.aton' and 'String.integer' pure native valueOf java.math.BigInteger.valueOf :: Long -> Integer -- arithmetic operations pure native + add :: Integer -> Integer -> Integer pure native * multiply :: Integer -> Integer -> Integer pure native - subtract :: Integer -> Integer -> Integer pure native quot divide :: Integer -> Integer -> Integer pure native rem remainder :: Integer -> Integer -> Integer --- /Warning/! Throws @ArithmeticException@ when divisor is negative. pure native nMod mod :: Integer -> Integer -> Integer pure native abs :: Integer -> Integer pure native negate :: Integer -> Integer -- relational pure native compareTo :: Integer -> Integer -> Int pure native max :: Integer -> Integer -> Integer pure native min :: Integer -> Integer -> Integer -- shift pure native bshr shiftRight :: Integer -> Int -> Integer pure native bshl shiftLeft :: Integer -> Int -> Integer --- unsigned right shift on big integers does not really make sense ... b `ushr` i = abs b `bshr` i -- bit arithmetic pure native bor or :: Integer -> Integer -> Integer pure native band and :: Integer -> Integer -> Integer pure native bxor xor :: Integer -> Integer -> Integer pure native bcmpl not :: Integer -> Integer -- miscellanous pure native bitLength :: Integer -> Int pure native toString :: Integer -> String pure native sign signum :: Integer -> Int pure native long longValue :: Integer -> Long pure native int intValue :: Integer -> Int pure native hashCode :: Integer -> Int pure native gcd :: Integer -> Integer -> Integer {-- * 'Long' values are based on Java's primitive @long@ values. * * According to the Java Language Specification, @long@ values are 64 bit wide signed two's complement integers (§4.2). Java operations on @long@ do not indicate overflow or underflow in any way (§4.2.2). Instead, just the low 64 bits of every result are retained. -} data Long = native long where --- Convert an 'Long' to a 'Float', i.e. @42L.float == 42.0f@. --- For large numbers, the result may have been be rounded. pure native float java.lang.Float.valueOf :: Long -> Float --- Convert an 'Long' to a 'Double', i.e. @42L.double == 42.0@. --- For large numbers, the result may have been be rounded. pure native double java.lang.Double.valueOf :: Long -> Double --- Uses a java cast to convert a 'Long' to an 'Int'. This is a /narrowing primitive conversion/ in java parlance. pure native int "(int)" :: Long -> Int --- Computes binary /or/ of two long integers. Uses the java @|@-operator. pure native bor "|" :: Long -> Long -> Long --- Computes binary /exclusive or/ of two long integers. Uses the java @^@-operator. pure native bxor "^" :: Long -> Long -> Long --- Computes binary /and/ of two integers. Uses the java @&@-operator. pure native band "&" :: Long -> Long -> Long --- hash code is upper half and lower half xor'ed hashCode l = (int l).bxor (int (l `bshr` 32)) --- 'Char' values are based on Java's primitive @char@ values. data Char = native char where {-- * @c.ord@ is the ordinal (integer) value of the character @c@. * It holds: @c.ord.char@ == @c@, see 'Int.char'. * (But note that @i.char.ord@ is not necessarily @i@) -} pure native ord "(int)" :: Char -> Int pure native hashCode "(int)" :: Char -> Int pure native isLowerCase java.lang.Character.isLowerCase :: Char -> Bool pure native toLowerCase java.lang.Character.toLowerCase :: Char -> Char pure native isUpperCase java.lang.Character.isUpperCase :: Char -> Bool pure native toUpperCase java.lang.Character.toUpperCase :: Char -> Char pure native isWhitespace java.lang.Character.isWhitespace :: Char -> Bool pure native isLetterOrDigit java.lang.Character.isLetterOrDigit :: Char -> Bool {-- 'String' values are based on Java's @java.lang.String@ objects. 'String' is an alias for 'StringJ' 'Char' -} type String = StringJ Char {-- For technical reasons, the native string type is defined with a phantom type, which allows us to treat strings like character lists. The following rules apply: - There must be no polymorphic non empty string. Trying to extract elements from it with 'itemAt' would fail with an exception at runtime. - Every function with return type ('StringJ' a) must either take one or more arguments of the same type which it manipulates, or it must return the empty string. In the former case, the elements of the result string must all be computed from the elements of the argument strings. -} protected data StringJ a = native java.lang.String where --- The length of a 'String' pure native length :: StringJ a -> Int --- Polymorphic variant of 'elemAt' --- Always returns a character (what else?) for nonempty strings. pure native itemAt frege.RT.itemAt :: StringJ a -> Int -> a {-- Like 'String.int', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -} pure native atoi java.lang.Integer.parseInt :: String -> Int {-- Like 'String.long', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -} pure native atol java.lang.Long.parseLong :: String -> Long {-- Like 'String.float', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -} pure native atof java.lang.Float.parseFloat :: String -> Float {-- Like 'String.double', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -} pure native atod java.lang.Double.parseDouble :: String -> Double {-- Like 'String.integer', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -} pure native aton new :: String -> Integer {-- Safe way to parse an integer from a string. @java.lang.NumberFormatException@ will be catched and returned as 'Left' value. When the parse succeeds, the integer is returned in the 'Right' value. Use like this: > case s.int of > Left exc -> ... // s is not well formed > Right i -> ... // the parsed value is in i -} pure native int java.lang.Integer.parseInt :: String -> Exception Int --- Safe way to parse a long integer from a string. See 'String.int' pure native long java.lang.Long.parseLong :: String -> Exception Long --- Safe way to parse a 'Float' value from a string. See 'String.int' pure native float java.lang.Float.parseFloat :: String -> Exception Float --- Safe way to parse a 'Double' value from a string. See 'String.int' pure native double java.lang.Double.parseDouble :: String -> Exception Double --- Safe way to parse a big 'Integer' value from a string. See 'String.int' pure native integer new :: String -> Exception Integer --- retrieve character at index pure native charAt :: String -> Int -> Char --- Get character at index. --- This will allow to use a string like an array, e.g. @"xyz".[1]@ pure native frozenGetAt charAt :: String -> Int -> Char pure native elemAt charAt :: String -> Int -> Char --- interpret this string as regex (unsafe, does not catch exceptions) --- see 'regcomp' for an alternative pure native compile java.util.regex.Pattern.compile :: String -> Regex --- quote regular expression metacharacters in string pure native quote java.util.regex.Pattern.quote :: String -> String --- quote replacement string metacharacters in string pure native quoteReplacement java.util.regex.Matcher.quoteReplacement :: String -> String --- convert to lower case pure native toLowerCase :: String -> String --- convert to upper case pure native toUpperCase :: String -> String --- 'String.compareTo' is used in the 'Ord' instance of 'String' pure native compareTo :: String -> String -> Int --- Concatenate two strings, uses Java's @+@ operator pure native ++ + :: StringJ a -> StringJ a -> StringJ a -- String concatenation --- get the has code pure native hashCode :: String -> Int {-- @substr s start end@ returns the sub string of @s@ that starts with the character at position @start@ and extends to the character at position @end-1@. This uses the native method @substring@ of class @java.lang.String@. It will throw an @IndexOutOfBoundsException@ if @start@ is negative or larger than @end@ or if @end@ is greater than the length of @s@. -} pure native substr substring :: StringJ a -> Int -> Int -> StringJ a {-- @strtail s n@ returns a new string that is a substring of string _s_. The substring begins with the character at the specified index and extends to the end of _s_. This uses the native method @substring@ of class @java.lang.String@. It will throw an @IndexOutOfBoundsException@ if _n_ is negative or larger than the length of _s_. -} pure native strtail substring :: StringJ a -> Int -> StringJ a --- compile a 'String' to a 'Regex' pure native regcomp java.util.regex.Pattern.compile :: String -> Exception Regex atoi (s::String) = s.atoi --- 'Float' values are based on Java's primitive @float@ values. {-- According to the Java Language Specification §4.2.3, @float@ values are 32-bit-precision binary floating point values. The values and the operations on it behave as speicified in the IEEE Standard for Binary Floating-Point Arithmetic. -} data Float = native float where {-- Returns the closest 'Int' value to the argument. The result is rounded to an integer by adding 1/2, taking the 'Float.floor' of the result, and casting the result to type int. The following property holds: > (f < Int.maxBound.float && f > Int.minBound.float) ==> > (f.int.float == (f + 0.5f).floor) Special cases: - If the argument is NaN, the result is 0. - If the argument is negative infinity or any value less than or equal to the value of 'Int.minBound', the result is equal to the value of 'Int.minBound'. - If the argument is positive infinity or any value greater than or equal to the value of 'Int.maxBound', the result is equal to the value of 'Int.maxBound'. -} pure native int java.lang.Math.round :: Float -> Int {-- Returns the largest (closest to positive infinity) value that is less than or equal to the argument and is equal to a mathematical integer. Special cases: - If the argument value is already equal to a mathematical integer, then the result is the same as the argument. - If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument. -} floor f = (Float.double f).floor.float --- Applies the java widening primitive conversion from @float@ to @double@. pure native double "(double)" :: Float -> Double --- bit representation of a float serves as hashCode pure native hashCode java.lang.Float.floatToIntBits :: Float -> Int --- 'Double' values are Java's primitive @double@ values. {-- According to the Java Language Specification §4.2.3, @double@ values are 64-bit-precision binary floating point values. The values and the operations on it behave as speicified in the IEEE Standard for Binary Floating-Point Arithmetic. -} data Double = native double where {-- Returns the closest 'Long' value to the argument. The result is rounded to an integer by adding 1/2, taking the 'Double.floor' of the result, and casting the result to type @long@. The following property holds: > (d < Long.maxBound.double && d > Long.minBound.double) ==> > (d.long.double == (d + 0.5d).floor) Special cases: - If the argument is NaN, the result is 0. - If the argument is negative infinity or any value less than or equal to the value of 'Long.minBound', the result is equal to the value of 'Long.minBound'. - If the argument is positive infinity or any value greater than or equal to the value of 'Long.maxBound', the result is equal to the value of 'Long.maxBound'. -} pure native long java.lang.Math.round :: Double -> Long {-- Returns the largest (closest to positive infinity) value that is less than or equal to the argument and is equal to a mathematical integer. Special cases: - If the argument value is already equal to a mathematical integer, then the result is the same as the argument. - If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument. -} pure native floor java.lang.Math.floor :: Double -> Double --- Applies the java narrowing primitive conversion from @double@ to @float@ pure native float "(float)" :: Double -> Float --- bit representation of a double pure native longBits java.lang.Double.doubleToLongBits :: Double -> Long --- the 'hashCode' is that of the 'Long' value used to represent the 'Double' hashCode d = (longBits d).hashCode {-- * 'Regex' values are based on Java's @java.util.regex.Pattern@ objects. * All regular expression literals are values of this type. -} data Regex = native java.util.regex.Pattern where pure native pattern :: Regex -> String --- create a 'Matcher' from a regular expression and a 'String' pure native matcher :: Regex -> String -> Matcher -- the following have been moved to Arrays -- pure native split :: Regex -> String -> StringArr {- Split a string around matches of a regular expression and return the result as list of strings. -} -- splitted r s = (split r s).toList {-- 'Matcher' values are based on Java's @java.util.regex.Matcher@ objects. Code generation relies on the existence of this type and its operations. The native 'Matcher' functions that correspond to java methods of the @java.util.regex.Matcher@ class that modify the state of the object they are invoked on ('Matcher.find', 'Matcher.matches', 'Matcher.replaceFirst', 'Matcher.replaceAll', 'Matcher.usePattern', 'Matcher.useAnchoringBounds') are implemented so that they make a copy of the 'Matcher' and invoke the impure java method on the copy. Frege 'Matcher's can thus be regarded as read-only values and the functions defined here as pure. If you need to pass a 'Matcher' to other native functions, be sure that the function is pure. If it is not because it would modify the matcher, and you do not need the match result, always pass a clone of the Matcher (see 'Matcher.clone') -} data Matcher = pure native java.util.regex.Matcher where pure native clone frege.RT.clone :: Matcher -> Matcher {-- Tries a match and if it succeeds, returns @Just m@, where @m@ is * a new 'Matcher' that contains the result. If there is no match, @Nothing@ * is returned. * * The following java fragment appends all matched substrings of a string: * > String s = "cats and dogs are not concatenated."; * > Pattern p = Pattern.compile("cat|dog"); * > String result = ""; * > Matcher m = p.matcher(s); * > while (m.find()) result += m.group(0); // "catdogcat" * The follwoing frege fragment computes the same result: > result = loop m "" where > s = "cats and dogs are not concatenated." > p = #cat|dog# > m = p.matcher s > loop :: Matcher -> String -> String > loop m1 r | Just m2 <- m1.find = loop m2 (r++m2.match) > | otherwise = r -} pure native find frege.RT.find :: Matcher -> Maybe Matcher --- Tries to match the entire string and returns @Just m@ on success and otherwise @Nothing@. pure native matches frege.RT.matches :: Matcher -> Maybe Matcher {-- Retrieves the input subsequence captured by the given group during the previous match operation. Capturing groups are indexed from left to right, starting at one. Group zero denotes the entire pattern, so the expression @(m.group 0)@ retrieves that portion of the input string that was matched by the pattern. If the match was successful but the group specified failed to match any part of the input sequence, then 'Nothing' is returned. Note that some groups, for example @(a?)@, match the empty string. This functon will return @Just ""@ when such a group successfully matches the empty string in the input. The folloing property holds for a 'Matcher' /m/ with input sequence /s/ and group index /g/: > isJust (m.group g) ==> (m.group g) == Just (s.substr (m.start g) (m.end g)) -} pure native group :: Matcher -> Int -> (Maybe String) {-- @Matcher.match m@ returns the input subsequence matched by the previous match. The result is 'undefined' if the last match was not successful. For a 'Matcher' @m@ with input sequence @s@, the following holds: > isJust (m.group 0) ==> unJust (m.group 0) == m.match Note that some patterns, for example @a?@, match the empty string. This method will return the empty string when the pattern successfully matches the empty string in the input. -} pure native match group :: Matcher -> String {-- Returns the start index of the subsequence captured by the given group during the previous match operation where group 0 denotes the entire pattern. If the specified capturing group failed to match, the return value will be -1. The follwoing property holds: > (m.group n == Nothing) ==> (m.start n < 0) -} pure native start :: Matcher -> Int -> Int {-- Returns the offset after the last character of the subsequence captured by the given group during the previous match operation where group 0 denotes the entire pattern. If the specified capturing group failed to match, the return value will be -1. The follwoing property holds: > (m.group n == Nothing) ==> (m.end n < 0) -} pure native end :: Matcher -> Int -> Int {-- Makes a new 'Matcher' and causes it to use a different 'Regex' for future matches. The original matchers position in the input and its last append position is copied, but information about the last match, if any, is not. This is most useful with patterns that start with the @\\G@ anchor. Note that, due to a java bug, if the last find operation matched the empty string, the next find will fail. For a workaround see 'Matcher.usePatternAndFind' -} pure native usePattern frege.RT.usePattern :: Matcher -> Regex -> Matcher {-- Makes a new 'Matcher' with a different 'Regex' and tries to find a match. If the last find on the original Matcher returned an empty result, it calls @mnew.find(morig.end(0))@ to work around a bug in the java API. Therefore, this function must only be used on a matcher whose last match attempt was successful. -} pure native usePatternAndFind frege.RT.usePatternAndFind :: Matcher -> Regex -> Maybe Matcher --- Requires or forbids the matcher to acknowledge anchors. pure native useAnchoringBounds frege.RT.useAnchoringBounds :: Matcher -> Bool -> Matcher {-- Returns the string representation of this matcher. The string representation of a 'Matcher' contains information that may be useful for debugging. The exact format is unspecified. -} pure native toString :: Matcher -> String {-- Replaces the first subsequence of the input sequence that matches the pattern with the given replacement string. This method scans the input sequence from the start looking for a match of the pattern. Characters that are not part of the match are appended directly to the result string; the match is replaced in the result by the replacement string. The replacement string may contain references to captured subsequences. Note that backslashes (\\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string. Dollar signs may be treated as references to captured subsequences as described above, and backslashes are used to escape literal characters in the replacement string. Given the regular expression @#dog#@, the input @"zzzdogzzzdogzzz"@, and the replacement string @"cat"@, an invocation of this function on a matcher for that expression would yield the string @"zzzcatzzzdogzzz"@. -} pure native replaceFirst frege.RT.replaceFirst :: Matcher -> String -> String --- Like 'Matcher.replaceFirst', but replaces all matches. pure native replaceAll frege.RT.replaceAll :: Matcher -> String -> String {-- * This is the principal return type for java methods that are expected to * throw exceptions. -} type Exception a = Either JException a {-- * We need to do some reflection from frege code. * For example, when we catch an 'JException' thrown from Java code. * we might want to know what it is. -} data Class = pure native java.lang.Class where pure native getName :: Class -> String pure native forName java.lang.Class.forName :: String -> Exception Class --- Frege wrapper for java exceptions. data JException = pure native java.lang.Exception where pure native getLocalizedMessage :: JException -> String pure native getMessage :: JException -> String pure native getClass :: JException -> Class --- give the name of this exception catched t = (JException.getClass t).getName {-- * Constructs a strict tuple. * The difference to '(,)' is that both argument values * will be evaluated before the tuple is constructed. Thus: * >fst (42; undefined) == undefined * >fst (42, undefined) == 42 * *Implementation specific:* The compiler will rewrite @(a;b)@ as * @(PreludeBase.strictTuple2 a b)@. -} pure native strictTuple2 PreludeBase.TTuple2.mk :: a -> b -> (a,b); --- Constructs a strict 3-tuple. See remarks for 'strictTuple2'. pure native strictTuple3 PreludeBase.TTuple3.mk :: a -> b -> c -> (a,b,c); --- Constructs a strict 4-tuple. See remarks for 'strictTuple2'. pure native strictTuple4 PreludeBase.TTuple4.mk :: a -> b -> c -> d -> (a,b,c,d); --- Constructs a strict 5-tuple. See remarks for 'strictTuple2'. pure native strictTuple5 PreludeBase.TTuple5.mk :: a -> b -> c -> d -> e -> (a,b,c,d,e); --- Constructs a strict 6-tuple. See remarks for 'strictTuple2'. pure native strictTuple6 PreludeBase.TTuple6.mk :: a -> b -> c -> d -> e -> f -> (a,b,c,d,e,f); --- Constructs a strict 7-tuple. See remarks for 'strictTuple2'. pure native strictTuple7 PreludeBase.TTuple7.mk :: a -> b -> c -> d -> e -> f -> g -> (a,b,c,d,e,f,g); --- Constructs a strict 8-tuple. See remarks for 'strictTuple2'. pure native strictTuple8 PreludeBase.TTuple8.mk :: a -> b -> c -> d -> e -> f -> g -> h -> (a,b,c,d,e,f,g,h); --- Constructs a strict 9-tuple. See remarks for 'strictTuple2'. pure native strictTuple9 PreludeBase.TTuple9.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> (a,b,c,d,e,f,g,h,i); --- Constructs a strict 10-tuple. See remarks for 'strictTuple2'. pure native strictTuple10 PreludeBase.TTuple10.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> (a,b,c,d,e,f,g,h,i,j); --- Constructs a strict 11-tuple. See remarks for 'strictTuple2'. pure native strictTuple11 PreludeBase.TTuple11.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> (a,b,c,d,e,f,g,h,i,j,k); --- Constructs a strict 12-tuple. See remarks for 'strictTuple2'. pure native strictTuple12 PreludeBase.TTuple12.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> (a,b,c,d,e,f,g,h,i,j,k,l); --- Constructs a strict 13-tuple. See remarks for 'strictTuple2'. pure native strictTuple13 PreludeBase.TTuple13.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> (a,b,c,d,e,f,g,h,i,j,k,l,m); --- Constructs a strict 14-tuple. See remarks for 'strictTuple2'. pure native strictTuple14 PreludeBase.TTuple14.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n); --- Constructs a strict 15-tuple. See remarks for 'strictTuple2'. pure native strictTuple15 PreludeBase.TTuple15.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o); --- Constructs a strict 16-tuple. See remarks for 'strictTuple2'. pure native strictTuple16 PreludeBase.TTuple16.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p); --- Constructs a strict 17-tuple. See remarks for 'strictTuple2'. pure native strictTuple17 PreludeBase.TTuple17.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q); --- Constructs a strict 18-tuple. See remarks for 'strictTuple2'. pure native strictTuple18 PreludeBase.TTuple18.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r); --- Constructs a strict 19-tuple. See remarks for 'strictTuple2'. pure native strictTuple19 PreludeBase.TTuple19.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s); --- Constructs a strict 20-tuple. See remarks for 'strictTuple2'. pure native strictTuple20 PreludeBase.TTuple20.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t); --- Constructs a strict 21-tuple. See remarks for 'strictTuple2'. pure native strictTuple21 PreludeBase.TTuple21.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u); --- Constructs a strict 22-tuple. See remarks for 'strictTuple2'. pure native strictTuple22 PreludeBase.TTuple22.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v); --- Constructs a strict 23-tuple. See remarks for 'strictTuple2'. pure native strictTuple23 PreludeBase.TTuple23.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w); --- Constructs a strict 24-tuple. See remarks for 'strictTuple2'. pure native strictTuple24 PreludeBase.TTuple24.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x); --- Constructs a strict 25-tuple. See remarks for 'strictTuple2'. pure native strictTuple25 PreludeBase.TTuple25.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> y -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y); --- Constructs a strict 26-tuple. See remarks for 'strictTuple2'. pure native strictTuple26 PreludeBase.TTuple26.mk :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> y -> z -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z); {- * @(try f x)@ is like @(f $ x)@ * but catches all exceptions that are thrown in @f@. To be used like * * > case try f x of * > Left exception -> ... * > Right result -> ... * * Note that 'try' is strict in both its arguments. The exceptions thrown * when the arguments are evaluated will *not* be catched. -} -- pure native try "PreludeBase._dollar.w" :: (a -> b) -> a -> Exception b --- @a `seq` b@ evaluates _a_ before it returns _b_ --- This is a right associative operator with precedence 15. seq !a b = b; --######### undefined things #################### data Undefined = pure native frege.RT.Undefined where pure native new :: String -> Undefined --- create an 'Undefined' value from a string and a cause pure native newSX new :: String -> JException -> Undefined {-- create an 'Undefined' value from a 'JException'. The message will be taken from the exception. -} newX :: JException -> Undefined newX jex = newSX ((("caused by ".++ jex.getClass.getName).++ ": ").++ jex.getMessage) jex --- Throw this 'Undefined', this will abort the computation evaluating it. --- Actually, the return type is not correct, since it never returns. pure native die :: Undefined -> Bool {-- convert an 'Undefined' value to a 'JException' This is actually a no-op, since @frege.RT.Undefined@ is a subclass of @java.lang.Exception@. However, the type checker knows nothing about subclasses. This function is used in the @Monad (Exception a)@. -} pure native toException "(java.lang.Exception)" :: Undefined -> JException --- This is the standard undefined value. undefined :: u undefined = error "undefined" --- Construct an undefined value with an informative message. error :: String -> u error s = if (Undefined.new s).die then error "a" else error "b" --- Constructs an undefined value from a java exception and throws it. throw u = if (Undefined.newX u).die then undefined else undefined -- Get the head element of a non empty list. The head of an empty list is 'undefined'. -- listhead (x:xs) = x -- listhead [] = error "List.head []" --######### boolean expr ######################## --- The Java @!@ operator on booleans pure native ! :: Bool -> Bool -- = if b then false else true; {-- The Java @&&@ operator on booleans. Note that since this is a native function, the second argument appears strict to the compiler when in fact it is lazy at the Java level. This can lead to inconsistent results in some cases. For example, the following program correctly prints @false@ in the first line of the output, but then aborts: > main _ = do > stdout << (false && undefined) << "\n" > stdout << conj false undefined << "\n" > where > conj a b = a && b Note that the very same behaviour is seen in the following java program > public class And { > static boolean undef() { > if (true) throw new Error("undefined"); > return false; > } > static boolean conj(boolean a, boolean b) { return a&&b; } > public static void main(String[] args) { > System.out.println(false && undef()); > System.out.println(conj(false, undef())); > } > } One could thus say that '&&' behaves exactly like the Java operator including the fact that it cannot be replaced by a function without changing the semantics of a program. For an alternative see 'und' -} pure native && :: Bool -> Bool -> Bool {-- The Java @||@ operator on booleans. Note that since this is a native function, the second argument appears strict to the compiler when in fact it is lazy at the Java level. This can lead to inconsistent results in cases where the wrong strictness of the second argument propagates to arguments of the function that contains an application of '||'. (The documentation for '&&' has an example.) See 'oder' for an alternative -} pure native || :: Bool -> Bool -> Bool {-- Like '&&', but second argument is lazy. The @`und`@ operator has the same precedence and arity as '&&'. The definition is > a `und` b = if a then b else false This should really be named _and_, but Haskell 2010 uses this already for lists. Hence we use the german word _und_. -} a `und` b = if a then b else false {-- Like '||', but second argument is lazy. The @`oder`@ operator has the same precedence and arity as '||'. The definition is > a `oder` b = if a then true else b This should really be named _or_, but Haskell 2010 uses this already for lists. Hence we use the german word _oder_. -} a `oder` b = if a then true else b {-- @not b@ is true if _b_ is false, otherwise true. Uses java's '!' operator. -} pure native not "!" :: Bool -> Bool {-- * @a ^^ b@ is true if either _a_ or _b_ is true, but not both. * > a ^^ b = if a then not b else b -} a ^^ b = if a then not b else b --######### expr identity ###################### {-- This checks for object identity or equality of primitive values using Java's @==@ operator. It evaluates its arguments, so undefined values cannot be compared. -} pure native === == :: a -> a -> Bool; {-- This checks for object identity or inequality of primitive values using Java's @!=@ operator. It evaluates its arguments, so undefined values cannot be compared. -} pure native !== != :: a -> a -> Bool; --########### class Ord - compare ordered things ################## --- The type of the result of '<=>' data Ordering = Lt | Eq | Gt {-- The 'Ord' class provides relational operators as well as the functions 'max' and 'min'. The default implementation defines them all in terms of the _compare_ operator '<=>'. Making some type an instance of 'Ord' makes it automatically an instance of 'Eq' if it is not one already and if it has an implementation for 'hashCode'. The operators '==' and '!=' will be defined in terms of '<=>'. Instances of 'Ord' can be derived automatically for algebraic data types when all elements of the type are themselves instances of 'Ord' and when the type is an instance of 'Eq'. -} class Ord Eq ord => ord where {-- This operator must be defined in all instances. It compares its operands and returns 'Lt' if the first is lower than the second, 'Gt' if the first is greater than the second and 'Ordering.Eq' otherwise. The following shall be invariantly true: > case a <=> b of { Eq -> a == b; _ -> a != b } -} (<=>) :: ord -> ord -> Ordering -- must be defined compare :: ord -> ord -> Ordering {-- Relational @<@ operator. Obeys the following laws: > if a < b && b < c then a < c > a < b == b > a -} (<) :: ord -> ord -> Bool {-- Relational @<=@ operator. Obeys the following laws: > if a <= b && b <= c then a <= c > a <= b == b >= a > a <= b == !(a > b) -} (<=) :: ord -> ord -> Bool {-- Relational @>@ operator. Obeys the following laws: > if a > b && b > c then a > c > a > b == b < a -} (>) :: ord -> ord -> Bool {-- Relational @>=@ operator. Obeys the following laws: > if a >= b && b >= c then a >= c > a >= b == b <= a > a >= b == !(a < b) -} (>=) :: ord -> ord -> Bool --- > max a b = if a > b then a else b max :: ord -> ord -> ord --- > min a b = if a < b then a else b min :: ord -> ord -> ord (a) < (b) = case a <=> b of { Lt -> true; _ -> false; } (a) <= (b) = case a <=> b of { Gt -> false; _ -> true; } (a) >= (b) = case a <=> b of { Lt -> false; _ -> true; } (a) > (b) = case a <=> b of { Gt -> true; _ -> false; } max a b = if a > b then a else b min a b = if a < b then a else b -- provided for Haskell compatibility as alias for '<=>' compare = (<=>) {-- This implementation for the ('==') operator is being used in instances of 'Ord' when the instantiated type is not already an instance of 'Eq'. -} (a) == (b) = case a <=> b of { Eq -> true; _ -> false; } {-- This implementation for the ('!=') operator is being used in instances of 'Ord' when the instantiated type is not already an instance of 'Eq'. -} (a) != (b) = case a <=> b of { Eq -> false; _ -> true; } --############# class Enum ############################################ {-- * Class 'Enum' defines operations on sequentially ordered types. * * A type that is an instance of 'Enum' is also an instance * of 'Ord' (and, in turn, of 'Eq'). * * Instances of 'Enum' may be derived for any enumeration type * (types whose constructors have no fields). * If there is no 'hashCode' provided, it will be the same as 'ord'. -} class Enum Ord e => e where {-- @ord e@ returns the ordinal number associated with the value @e@. For * enumeration types, 'ord' is the same as 'constructor', for 'Int', it is the * identity function. * Some types, like 'Long', cannot map all their values to 'Int', in such cases * the result of applying 'ord' may be meaningless. -} ord :: e -> Int {-- * This is the default implementation of the compare operator, * that makes each 'Enum' type an 'Ord' type automatically. * > a <=> b = (ord a).<=> (ord b) -} a <=> b = (ord a).<=> (ord b) {-- * @T.from i@ maps the 'Int' value @i@ to a value of @T@, such that > ord (T.from i) == i * unless there is no value @e@ of @T@ so that @ord e == i@. In the * latter case, the result is 'undefined'. -} from :: Int -> e --- @succ e@ is the successor of @e@ or 'undefined' if there is no such successor. succ :: e -> e --- @pred e@ is the predecessor of @e@ or 'undefined' if there is no predecessor. pred :: e -> e -- pred x = from (ord x - 1) -- succ x = from (ord x + 1) {-- @a .. b@ is the list @[a, succ a, succ (succ a), ..., b ]@ * if @a < b@, or [a] if @a == b@ or the empty list if @a > b@. -} (..) :: e -> e -> [e] (a) .. (b) | a < b = a:(succ a). .. b | a == b = [a] | otherwise = [] --- default implementation for 'Eq.hashCode' is same as 'ord' hashCode = ord instance Eq () where () != () = false () == () = true hashCode () = 42 --########### class Num - basic arithmetics ######################## {-- The 'Num' class provides the operators ('+'), ('-') and ('*') as well as some functions that are common for all numeric types. -} class Num Ord n => n where --- Computes the sum of two numbers (+) :: n -> n -> n --- Computes the difference of two numbers (-) :: n -> n -> n --- use @(subtract a)@ instead of @\\b -> b-a@ in sections subtract :: n -> n -> n --- Computes the product of two numbers (*) :: n -> n -> n --- Computes the absolute value abs :: n -> n --- Negates a number n such that if n is a number --- > n + negate n == 0 negate :: n -> n --- @sign n@ is -1 if n<0, 1 if n>0 and 0 otherwise sign :: n -> Int --- the number 1 in the instantiated type one :: n --- the number 0 in the instantiated type zero :: n abs n = if n < zero then zero-n else n negate n = zero-n subtract b a = a-b sign n = constructor (n <=> zero) - 1 --- converts an 'Int' value to the instantiated type fromInt :: Int -> n {-- Floating point number types may have special values for _infinity_ and _negative infinity_. @isFinite n@ yields @true@ if @n@ is an infinite value and @false@ in all other cases. The default implementation always returns @false@ so that implementors of instances for types without special values for infinity need not care. See also 'isNumber'. -} isInfinite :: n -> Bool isInfinite _ = false {-- Floating point number types may have a special values for _not a number_ (NaN). For example, @0d / 0d@ is NaN. @isNaN n@ yields @true@ if @n@ is the special value that indicates that @n@ is not a number and @false@ in all other cases. The default implementation always returns @false@ so that implementors of instances for types without such a special values need not care. See also 'isNumber'. -} isNaN :: n -> Bool isNaN _ = false {-- Returns @true@ if @n@ is neither infinite (see 'isInfinite') nor NaN (see 'isNaN'). Note that certain properties for funtions on numbers are true only under the assumption that the argument values are numbers. The default implementation is > isNumber n = !(isInfinite n) && !(isNaN n) so that the function should always compute the right answer as long as 'isInfinite' and 'isNaN' do. -} isNumber :: n -> Bool isNumber n = !(isInfinite n) && !(isNaN n) {-- * The 'Real' class provides the division operator ('/'). -} class Real Num r => r where --- the division operator (/) :: r -> r -> r {-- * 'Integer' is an instance of 'Ord' -} instance Ord Integer where a <=> b = (a.compareTo b).<=> 0 a > b = (a.compareTo b).> 0 a < b = (a.compareTo b).< 0 a >= b = (a.compareTo b).>= 0 a <= b = (a.compareTo b).<= 0 a == b = (a.compareTo b).== 0 a != b = (a.compareTo b).!= 0 {-- * 'Integer' is an instance of 'Enum' -} instance Enum Integer where --- @succ b@ is the same as @b + 1.big@ succ b = b + Integer.one --- @succ b@ is the same as @b + 1.big@ pred b = b - Integer.one --- @ord b@ is only defined if the value of b is in the range 'Int.minBound' .. 'Int.maxBound' ord b = b.int --- @Integer.from i@ is the same as @Int.big i@ from i = i.big ; {-- * 'Integer' is an instance of 'Integral' -} instance Integral Integer where fromInt i = Int.big i big b = b -- i am already big --- Class 'Integral' provides bit arithmetic, division and remainder operations for integral numbers. class Integral Num integ => integ where --- integer division div, quot :: integ -> integ -> integ --- Haskell compatibility quotRem, divMod :: integ -> integ -> (integ, integ) quotRem a b = (a `quot` b, a `rem` b) divMod a b = (a `div` b, a `mod` b) --- The remainder á la Java operator @%@ - @a `rem` b@ has same sign as @a@ --- > forAll arbitrary (\a -> forAll arbitrary (\b -> (a `quot` b) * b + (a `rem` b) = a --- This behaviour is the same as in Haskell rem :: integ -> integ -> integ mod :: integ -> integ -> integ --- This modulo operator works so that --- > forAll arbitrary (\a -> forAll arbitrary (\b -> (a `div` b) * b + (a `mod` b) = a)) --- In addition, it is the case that --- > forAll arbitrary (\a -> forAll arbitrary (\b -> @(a `quot` b) == (a `div` b) || (a `quot` b) == (a `div` b)-1)) a `mod` b = case a `rem` b of r | r == zero = r | (a >= zero) == (b >= zero) = r -- a and b have same sign | otherwise = r + b a `div` b = case a `quot` b of q | (a >= zero) == (b >= zero) = q -- a and b have same sign | q * b == a = q | otherwise = q-one --- binary and, supposed to work like Java @&@ on all integral types band :: integ -> integ -> integ --- binary exclusive or, supposed to work like Java @^@ on all integral types bxor :: integ -> integ -> integ --- binary or, supposed to work like Java @|@ on all integral types bor :: integ -> integ -> integ --- binary left shift, supposed to work like Java @<<@ on all integral types bshl :: integ -> Int -> integ --- binary right shift, supposed to work like Java @>>@ on all integral types bshr :: integ -> Int -> integ --- unsigned right shift, supposed to work like Java @>>>@ on all integral types ushr :: integ -> Int -> integ --- one's complement, supposed to work like Java operator @~@ bcmpl :: integ -> integ bcmpl x = x `bxor` fromInt (-1) --- every integral number can be converted to a big 'Integer' big :: integ -> Integer -- ----------------------------------------------------- {-- 'gcd' @x y@ is the non-negative factor of both @x@ and @y@ of which every common factor of @x@ and @y@ is also a factor; for example 'gcd' @4 2 = 2@, @'gcd' (-4) 6 = 2@, @'gcd' 0 4@ = @4@. @'gcd' 0 0@ = @0@. (That is, the common divisor that is \"greatest\" in the divisibility preordering.) Note: Since for signed fixed-width integer types, 'abs' 'minBound' < @0@, the result may be negative if one of the arguments is 'minBound' (and necessarily is if the other is @0@ or 'minBound') for such types. -} gcd :: integ -> integ -> integ gcd x y = gcd' (abs x) (abs y) where gcd' a b | b == zero = a | otherwise = gcd' b (a `rem` b) --- 'lcm' @x y@ is the smallest positive integer that both @x@ and @y@ divide. lcm :: integ -> integ -> integ lcm x y | x == zero || y == zero = zero | otherwise = abs ((x `quot` (gcd x y)) * y) even, odd :: integ -> Bool even n = n `band` one == zero odd n = n `band` one != zero --############ Int instances & functions ############################ instance Eq Int where --- Uses the java @==@ operator for comparision of 'Int' values. pure native == :: Int -> Int -> Bool --- Uses the java @!=@ operator for comparision of 'Int' values. pure native != :: Int -> Int -> Bool instance Ord Int where --- Uses the java @<=@ operator for comparision of 'Int' values. pure native <= :: Int -> Int -> Bool --- Uses the java @>=@ operator for comparision of 'Int' values. pure native >= :: Int -> Int -> Bool --- Uses the java @<@ operator for comparision of 'Int' values. pure native < :: Int -> Int -> Bool --- Uses the java @>@ operator for comparision of 'Int' values. pure native > :: Int -> Int -> Bool (<=>) :: Int -> Int -> Ordering (a) <=> (b) = if ab then Gt else Eq instance Num Int where --- Uses the java @+@ operator to add 2 'Int' values. pure native + :: Int -> Int -> Int --- Uses the java @\*@ operator to multiply 2 'Int' values. pure native * :: Int -> Int -> Int --- Uses the java @-@ operator to subtract one 'Int' value from another. pure native - :: Int -> Int -> Int --- the integer constant 0 zero = 0 --- the integer constant 1 one = 1 {-- Returns the negated argument if it is negative, otherwise the argument itself. This does not work for 'Int.minBound' since there is no corresponding positive value that can be represented as an 'Int'. Rather > abs Int.minBound == Int.minBound -} abs i = if i < 0 then negate i else i {-- @negate i@ computes @0-i@ using the java negation operator @-@. This does not work for 'Int.minBound' since there is no corresponding positive value that can be represented as an 'Int'. Rather > negate Int.minBound == Int.minBound -} pure native negate "-" :: Int -> Int --- For 'Int' values, this is the identity function. fromInt i = i instance Eq Long where --- Uses the java @==@ operator for comparision of 'Long' values. pure native == :: Long -> Long -> Bool --- Uses the java @!=@ operator for comparision of 'Long' values. pure native != :: Long -> Long -> Bool instance Ord Long where --- Uses the java @<=@ operator for comparision of 'Long' values. pure native <= :: Long -> Long -> Bool --- Uses the java @>=@ operator for comparision of 'Long' values. pure native >= :: Long -> Long -> Bool --- Uses the java @<@ operator for comparision of 'Long' values. pure native < :: Long -> Long -> Bool --- Uses the java @>@ operator for comparision of 'Long' values. pure native > :: Long -> Long -> Bool (<=>) :: Long -> Long -> Ordering (a) <=> (b) = if ab then Gt else Eq instance Num Long where --- Uses the java @+@ operator to add two 'Long' values. pure native + :: Long -> Long -> Long --- Uses the java @\*@ operator to multiply two 'Long' values. pure native * :: Long -> Long -> Long --- Uses the java @-@ operator to subtract a 'Long' value from another. pure native - :: Long -> Long -> Long --- The constant @0L@. zero = 0L --- The constant @1L@. one = 1L {-- Returns the negated argument if it is negative, otherwise the argument itself. This does not work for 'Long.minBound' since there is no corresponding positive value that can be represented as a 'Long'. Rather > abs Long.minBound == Long.minBound -} abs i = if i < 0L then 0L-i else i {-- @negate a@ computes @0L-a@ using the java negation operator @-@. This does not work for 'Long.minBound' since there is no corresponding positive value that can be represented as a 'Long'. Rather > negate Long.minBound == Long.minBound -} pure native negate "-" :: Long -> Long --- applys the widening primitive conversion (JLS §5.1.2) from @int@ to @long@ fromInt i = i.long {-- * A class for data types that have a lower and an upper bound. * * Instances of 'Bounded' can be derived automatically for enumeration types. -} class Bounded b where --- the lower bound minBound :: b --- the upper bound maxBound :: b instance Bounded Int where --- the smallest 'Int' value -2147483648 (or -(2**31)) minBound = 0x80000000 --- the largest 'Int' value 2147483647 (or (2**31)-1) maxBound = 0x7fffffff instance Enum Int where --- > ord i = i ord (i::Int) = i --- > from i = i from (i::Int) = i --- @pred i@ is the same as @i-1@ except for @pred Int.minBound@, which is 'undefined' pred i | i > Int.minBound = i-1 | otherwise = error "pred Int.minBound" --- @succ i@ is the same as @i+1@ except for @succ Int.maxBound@, which is 'undefined' succ i | i < Int.maxBound = i+1 | otherwise = error "succ Int.maxBound" instance Bounded Long where --- the smallest 'Long' value -9223372036854775808 (or -(2**63)) minBound = 0x8000000000000000L --- the largest 'Long' value 9223372036854775807 (or (2**63)-1) maxBound = 0x7fffffffffffffffL instance Enum Long where --- @ord l@ is only valid if @Int.minBound.long <= l && l <= Int.maxBound@ ord (i::Long) = i.int; --- @Long.from i@ returns a 'Long' with the same numeric value as @i@. from (i::Int) = i.long; --- @pred a@ is the same as @a-1L@ except for @pred Long.minBound@, which is 'undefined' pred i | i > Long.minBound = i-1L | otherwise = error "pred Long.minBound" --- @succ a@ is the same as @a+1L@ except for @succ Long.maxBound@, which is 'undefined' succ i | i < Long.maxBound = i+1L | otherwise = error "succ Long.maxBound" instance Integral Int where pure native rem % :: Int -> Int -> Int pure native quot / :: Int -> Int -> Int pure native bshl "<<" :: Int -> Int -> Int pure native bshr ">>" :: Int -> Int -> Int --- unsigned right shift pure native ushr ">>>" :: Int -> Int -> Int pure native bcmpl "~" :: Int -> Int big l = Integer.valueOf l.long instance Integral Long where pure native rem % :: Long -> Long -> Long pure native quot / :: Long -> Long -> Long pure native bshl "<<" :: Long -> Int -> Long pure native bshr ">>" :: Long -> Int -> Long pure native bcmpl "~" :: Long -> Long big l = Integer.valueOf l --- unsigned right shift pure native ushr ">>>" :: Long -> Int -> Long --############# Bool instances ######################################## instance Ord Bool where false < true = true _ < _ = false true > false = true _ > _ = false false <= _ = true true <= b = b false >= b = !b true >= _ = true true <=> false = Gt false <=> true = Lt _ <=> _ = Eq instance Bounded Bool where minBound = false maxBound = true instance Enum Bool where ord false = 0 ord true = 1 from 0 = false from _ = true -- nonzero is true pred true = false pred _ = error "pred false" succ false = true succ true = error "succ true" --############## String instances ############### instance Eq String where pure native == equals :: String -> String -> Bool (!=) :: String -> String -> Bool a != b = !(a==b) instance Ord String where (<=>) :: String -> String -> Ordering (>) :: String -> String -> Bool (<) :: String -> String -> Bool (>=) :: String -> String -> Bool (<=) :: String -> String -> Bool a <=> b = (a.compareTo b).<=> 0 a > b = (a.compareTo b).> 0 a < b = (a.compareTo b).< 0 a >= b = (a.compareTo b).>= 0 a <= b = (a.compareTo b).<= 0 --################# Char instances ############# instance Eq Char where pure native == :: Char -> Char -> Bool pure native != :: Char -> Char -> Bool instance Ord Char where (<=>) :: Char -> Char -> Ordering a <=> b = a.ord.<=> b.ord pure native <= :: Char -> Char -> Bool pure native >= :: Char -> Char -> Bool pure native < :: Char -> Char -> Bool pure native > :: Char -> Char -> Bool instance Bounded Char where pure native minBound java.lang.Character.MIN_VALUE :: Char pure native maxBound java.lang.Character.MAX_VALUE :: Char instance Enum Char where pure native from "(char)" :: Int -> Char pred c = Char.from (Char.ord c - 1) succ c = Char.from (Char.ord c + 1) chr i = Char.from i pure native ctos java.lang.Character.toString :: Char -> String --################# Float Instances ############# instance Eq Float where pure native == :: Float -> Float -> Bool pure native != :: Float -> Float -> Bool instance Ord Float where pure native <= :: Float -> Float -> Bool pure native >= :: Float -> Float -> Bool pure native < :: Float -> Float -> Bool pure native > :: Float -> Float -> Bool (<=>) :: Float -> Float -> Ordering a <=> b = if ab then Gt else Eq instance Real Float where pure native + :: Float -> Float -> Float pure native - :: Float -> Float -> Float pure native * :: Float -> Float -> Float pure native / :: Float -> Float -> Float zero = 0.0f one = 1.0f pure native negate "-" :: Float -> Float fromInt i = i.float pure native isInfinite java.lang.Float.isInfinite :: Float -> Bool pure native isNaN java.lang.Float.isNaN :: Float -> Bool -- ################# Double Instances ############# instance Eq Double where pure native == :: Double -> Double -> Bool pure native != :: Double -> Double -> Bool instance Ord Double where pure native <= :: Double -> Double -> Bool pure native >= :: Double -> Double -> Bool pure native < :: Double -> Double -> Bool pure native > :: Double -> Double -> Bool (<=>) :: Double -> Double -> Ordering a <=> b = if ab then Gt else Eq instance Real Double where pure native + :: Double -> Double -> Double pure native - :: Double -> Double -> Double pure native * :: Double -> Double -> Double pure native / :: Double -> Double -> Double zero = 0.0 one = 1.0 pure native negate "-" :: Double -> Double fromInt i = i.double pure native isInfinite java.lang.Double.isInfinite :: Double -> Bool pure native isNaN java.lang.Double.isNaN :: Double -> Bool -- ################# Misc. types and derivations ############# -- derive Show () -- derive Show Ordering instance Eq Eq a => [a] where --- two lists are equal if their heads and tails are equal or if the lists are empty (a:as) == (b:bs) | a == b = as == bs | otherwise = false [] == [] = true _ == _ = false hashCode [] = 31 hashCode as = loop as 32 where loop (a:as) !acc = loop as (acc*31 + hashCode a) loop [] acc = acc -- derive Ord Ord a => [a] data Maybe a = Nothing | Just a {-- The 'maybe' function takes a default value, a function, and a 'Maybe' value. If the 'Maybe' value is 'Nothing', the function returns the default value. Otherwise, it applies the function to the value inside the 'Just' and returns the result. -} maybe d f (Just x) = f x maybe d f Nothing = d data Either a b = Left a | Right b -- derive Eq Either a b -- derive Ord Either a b -- derive Show Either a b either left right (Left x) = left x either left right (Right x) = right x {-- * > string =~ regex * tries to match _string_ against _regex_ and returns * @Just matcher@ if it succeeds, @Nothing@ otherwise. -} (s) =~ (p::Regex) = (p.matcher s).find {-- * >string ~ regex * @true@ if _string_ matches _regex_, @false@ otherwise -} (s) ~ (p::Regex) = case (p.matcher s).find of Just _ -> true Nothing -> false {-- * > s !~ p == !(s ~ p) -} (s) !~ (p) = !(s ~ p) {-- * > ("string" ~~ #r??#) == Just "rin" * Tries a match and returns @Just x@ where * _x_ is the matched substring or @Nothing@ if there was no match. * -} s ~~ r = case s =~ r of Just m -> m.group 0 Nothing -> Nothing {-- * > string ~~~ regex * Matches _string_ with _regex_ and returns a function * that can be used to extract the matched part of the string and the * captured substrings. * > let f = "frege" ~~~ #(..).(..)# * > in [ f i | i <- 0..3 ] * yields * >[Just "frege", Just "fr", Just "ge", Nothing] -} s ~~~ r = case s =~ r of Just m -> m.group Nothing -> const Nothing {-- * @m ?~ p@ binds pattern _p_ to the matcher _m_ * and tries a match. There must have been a successful * match on _m_ before. * Returns 'Nothing' if match fails, else ('Just' @m@). * This function is most usefull in conjunction with patterns that * use the G-anchor when one wants to extract * multiple differnt adjacent items from a string. -} (m::Matcher) ?~ (p) = m.usePatternAndFind p {-- * > m /~ p * is like * > m ?~ p * but instead of the * matcher it returns the matched string, if any. -} (m) /~ (p) = case m ?~ p of Just m -> Matcher.group m 0 Nothing -> Nothing --- return the first element of a 2-tuple fst (a, _) = a --- return the second element of a 2-tuple snd (_, a) = a -- derive Eq (a,b) -- derive Ord (a,b) -- derive Show (a,b) -- derive Eq (a,b,c) -- derive Ord (a,b,c) -- derive Show (a,b,c) {- more tuple stuff in Tuples.fr -} -- function stuff {-- Function composition. @(f <~ g)@ is a function whose argument is passed to /g/, and the result to /f/, yielding the overall result. One can imagine that the data flow from right to left through a function pipe. > (a) <~ (b) = \x -> a (b x) -} (a) <~ (b) = \x -> a (b x) {-- Function composition. @(f ~> g)@ is a function whose argument is first passed to /f/, and the result to /g/, yielding the overall result. One can imagine that the data flows from left to right through a function pipe. > (a) ~> (b) = \x -> b (a x) -} (a) ~> (b) = \x -> b (a x) {-- @a $ b@ is the same as @a b@, but because of '$''s low precedence one can write @f $ x+y@ instead of @f (x+y)@. Also, becuase '$' is right associative, @f $ g $ h y@ is @f (g (h y))@ -} (a) $ (b) = a b --- Same as `$` but argument is strict a $! !b = a b --- The identity function id x = x --- @const a@ is a function that returns _a_ regardless of its argument. const a _ = a --- @asTypeOf a b@ is _a_ with the type of _b_. --- This is a type restricted version of 'const'. asTypeOf :: a -> a -> a asTypeOf a _ = a --- Exchange first and second argument of a function, i.e. --- > flip f a b = f b a flip f a b = f b a --- Passes the elements of a 2-tuple as arguments to a function. uncurry f (a,b) = f a b --- @curry f@ passes the next two arguments as 2-tuple to _f_ curry f a b = f (a,b) --- Another operator for function composition, which is identical to '<~' --- > (f • g) a = f (g a) (•) = \f\g\a -> f (g a) --- In patterns, the \@-operator is used to bind a name to a complex pattern --- > f (x@a:as) = e --- is the same as --- > f arg = case arg of { x -> case x of { a:as -> e }} (@) = (•) {-- * @using f@ applies a projection function _f_ on both sides of '=='. * The example for 'uniqBy' could be written easier * > uniqBy (using fst) [(1, 1), (2, 2), (2, 3), (3,4), (2,5)] -} using f a b = f a == f b {-- * @comparing f@ applies a proejction function on both sides of '<=>'. * Example usage: * > sortBy (comparing snd) [(1, "z"), (2, "b")] == [(2, "b"), (1, "z")] -} comparing f a b = f a <=> f b --- this is just an alias for 'comparing' ascending = comparing {-- * @descending f@ applies a projection function on both sides of '<=>', but flips arguments. * Example usage: * > sortBy (descending fst) [(1, "z"), (2, "b")] == [(2, "b"), (1, "z")] -} descending f a b = f b <=> f a -- #################################################################### -- ###################### monad stuff ################################# -- #################################################################### {-- * @(ST s a)@ is an abstract data type and is * a computation that encapsulates side effects in state thread @s@ * and returns a value of type @a@. * The type @s@ can be understood as a compiler generated unique index for state threads. * Every state thread is independend of each other and keeps track of mutable variables * created in it. For detailed information, read the paper _Lazy Functional State Threads_. * Every mutable native data type will have a phantom type paramter @s@ * that tells to what state thread the value belongs. For example, the @new@ method of * the java class @java.util.Date@ could be accessed like this: > data Date s = native java.util.Date where > native new :: () -> ST s (Date s) * Inside ST actions, Date values can be created and manipulated with * impure native methods at will. However, such a value can never escape * its ST thread. * Because @ST s@ is an instance of 'Monad', ST actions can be combined, which * ensures sequenced execution. For example, we could add another method * to the Date type that converts the date to a string: * > native toString :: Date s -> ST s String * and a computation which yields the current time in string form: * > now = do * > date <- Date.new () * > return date.toString * This looks almost like java already! @now@ has type @ST s String@ and we can run * the computation with @now.run@ (see 'ST.run' below), which gives us a nice, pure, immutable, * functional correct 'String' value. * The 'IO' type is just an alias for 'ST' 'RealWorld', and can be thought of as * indexing a unique global state thread. * Values of type 'IO' @a@ are also called _IO actions_. * Any ST value can also be used in the IO thread. * This guarantees that * - any computation with side effect is sequenced through the ST-Monad * - any function whose return type is not @IO something@ does not have side effects, * as long as no impure native function or value is deliberately declared to be pure. -} abstract data ST s a = ST (s -> a) where private app :: ST s a -> s -> a private app (ST x) b = x b {-- Run a stateful action with type @ST r a@ and return a result of type _a_. The overall computation @ST.run st@ is pure, though inside the 'ST' action local mutable state can be employed. This is possible only if the result type @a@ of the state action does *not* mention @r@ and if @r@ is a type variable. Hence, it is not possible to 'run' an 'IO' action. -} public run :: forall a . (forall ß. ST ß a) -> a public run stx = (stx.app "stateful") public performUnsafe (ST x) = (x RealWorld.RealWorld) -- The function that does the real work for 'ST.>>=' -- It is defined public in order to make inlining possible -- public bind :: (x -> y) -> (y -> ST x z) -> x -> z -- public bind a k u = case a u of -- !v -> case k v of ST.ST b -> b u public return a = ST (const a) public (ST !a) >>= k = ST (\u -> case a u of !v -> case k v of ST.ST b -> b u ) {-- * This abstract data type identifies the global state (disk, network, you name it). * Values of type 'ST' 'RealWorld' @a@ are likely to perform input/output, manipulate * global data and so on. -} abstract data RealWorld = RealWorld {-- * Some native values can be detached from the stateful realm so as to make it possible * to apply them to pure (native) functions, see 'Freezable'. * * Such values will have 'Immutable' as last type argument. -} abstract data Immutable = Immutable --- @IO a@ is an abbrevation for 'ST' 'RealWorld' @a@ type IO = ST RealWorld --- @Mutable MyType s@ is an abbrevation for 'ST' @s (MyType s)@ type Mutable n s = ST s (n s) --- @Frozen MyType@ is an abbrevation for @MyType Immutable@ type Frozen n = n Immutable -- --- @IOJ T@ is an abbreviation for 'IO' (T 'RealWorld') -- --- @STJ s T@ is an abbreviation for 'ST' s (T s) -- type IOJ j = STJ RealWorld j -- type STJ s j = ST s (j s) -- ########## Variables ########################### data STRef a s = native frege.rt.Ref where native new :: a -> Mutable (STRef a) s native get :: STRef a s -> ST s a native put :: STRef a s -> a -> ST s () type IORef a = STRef a RealWorld {-- * @State s a@ is an abstrac data type that resembles a stateful computation * with state _s_ and result _a_, * i.e. functions of type @s -> (a, s)@ * where the state is immutable. -} abstract data State s a = State (s -> (a, s)) where --- run a stateful computation public run (State x) s = x s --- get the current 'State' public get = State (\state -> (state; state)) --- update the 'State' public put x = State (const ((); x)) --- change the 'State' public change f = State (\state -> ((); f state)) --- lift a value to the 'State' monad public return a = State (strictTuple2 a) --- monadic bind for the 'State' monad public State !a >>= k = State (\s -> case a s of (v, !s') -> case k v of State.State b -> b s' ) public a >> b = State.>>= a (const b) --- print a 'string' to the standard error stream native traceStr java.lang.System.err.print :: String -> IO () --- print a 'string' to the standard error stream and append a new line. native traceStrLn java.lang.System.err.println :: String -> IO () --- print a 'string' to the standard output stream native printStr java.lang.System.out.print :: String -> IO () --- print a 'string' to the standard output stream and append a new line. native printStrLn java.lang.System.out.println :: String -> IO ()