Skip to content
2034 lines (1688 sloc) 82.6 KB
-- Making the license a package comment causes it to be part of every
-- runnable frege code.
{--
Copyright © 2011 - 2015, 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 implicitly 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 programmatically 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.
-}
{-
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, const, asTypeOf, $!, $, flip, curry, und, oder,
chr, bool,
ST.>>=,
-- State.put, State.change,
Int.fromInt, Double.fromDouble
)
where
{-
* Here are the standard operators in precedence order
* (higher numbers bind more tightly)
* This is so that @!x@ can be thought of having
* precedence 18 and @(f x)@ can be thought of as having precedence 17
-}
infixr 15 `^`
infixl 14 `*` `/` `mod` `rem` `div` `quot`
infixl 13 `+` -
infixr 13 `++`
infixl 12 `shiftL` `shiftR` `rotateL` `rotateR` `ushiftR`
infixl 11 `.&.`
infixl 10 `.|.` `.^.`
infix 9 `<=` `>=` `<` `>`
infix 8 `<=>` `compare`
infix 7 `==` `!=` `===` `!==` -- `<>`
infixr 6 `&&` `und`
infixr 5 `||` `oder` `^^`
infixr 4 `:` `!:`
infixl 3 `>>=` -- monad bind
infixr 2 `@` `seq` -- so that x@a:bs is parsed as x@(a:bs)
infixl 2 either
infixl 1 on
infixr 1 `$` `$!`
-- -----------------------------------------------------------------------------
-- CLASS SECTION
-- -----------------------------------------------------------------------------
{--
The type 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.
--- The basic law of philosophy
--- > 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
--- Compute a hash code.
--- The following 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 hash codes more likely than not.
{--
The hash code in derived instances for algebraic data types is computed as follows:
> hashCode v = case v of
> Con_1 f_1 ... f_k -> fold mkhash 1 [1, hashCode f_1, ..., hashCode f_k ]
> ...
> Con_n f_1 ... f_k -> fold mkhash 1 [n, hashCode f_1, ..., hashCode f_k ]
> where mkhash a b = (31 * a) + b
Here, the @Con_i@ with @i>0@ are the constructors, and in each clause
the @f_j@ with @j >= 0@ are bound to the fields of the constructor under
consideration.
-}
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 function types, product types and native types or
* the _constructor number_ for constructed types. The _constructor number_
* is a small integer associated with every constructed value. It indicates
* the data constructor a value was constructed with.
*
* 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.runtime.Runtime.constructor" :: a -> Int
--######### 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
{--
For compatibility with Haskell, the 'HaskellBool' type defines
constructors 'True' and 'False'.
When the identifiers @True@ or @False@ are used in patterns or expressions,
qualified or unqualified, and name resolution detects that they
resolve to 'PreludeBase.HaskellBool.True' or 'PreludeBase.HaskellBool.False'
they will be replaced by literals @true@ or @false@.
This is, of course, a hack, but I see no other way to bridge the gap between
redefinable constructor ids and literals. For example, we couldn't simply
define @True@ as another literal keyword, because some Haskell code
might use @Prelude.True@ or could have code like.
> import Prelude hiding(True, False)
> data TriBool = False | Perhaps | True
-}
data HaskellBool = False --- will be replaced by literal @false@
| True --- will be replaced by literal @true@
{--
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
{--
warning: will soon be replaced with bool
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
{--
This is used by code generation when a conditional expression
appears in a lazy context, i.e.
> (42, if foo then bar else baz)
@bool a b c@ evaluates to @a@ if @c@ is @true@, otherwise to @b@.
-}
bool a b c = if c then a else b
{--
'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 specialized 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 (.|.) "|" :: Int -> Int -> Int
--- Computes binary /exclusive or/ of two integers. Uses the java @^@-operator.
pure native (.^.) "^" :: Int -> Int -> Int
--- Computes binary /and/ of two integers. Uses the java @&@-operator.
pure native (.&.) "&" :: Int -> Int -> Int
--- The number of bits used to represent an int value in two's complement binary form
pure native size java.lang.Integer.SIZE :: Int
pure native shiftL "<<" :: Int -> Int -> Int
pure native shiftR ">>" :: Int -> Int -> Int
--- unsigned right shift
pure native ushiftR ">>>" :: Int -> Int -> Int
pure native complement "~" :: Int -> Int
--- Returns the value obtained by rotating the two's complement binary representation of the specified int value left
--- by the specified number of bits.
pure native rotateL java.lang.Integer.rotateLeft :: Int -> Int -> Int
--- Returns the value obtained by rotating the two's complement binary representation of the specified int value
--- right by the specified number of bits.
pure native rotateR java.lang.Integer.rotateRight :: Int -> Int -> Int
-- Compare 2 integers, 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', 'frege.prelude.PreludeText#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 shiftR shiftRight :: Integer -> Int -> Integer
pure native shiftL shiftLeft :: Integer -> Int -> Integer
--- unsigned right shift on big integers does not really make sense ...
b `ushiftR` i = abs b `shiftR` i
-- bit arithmetic
pure native (.|.) or :: Integer -> Integer -> Integer
pure native (.&.) and :: Integer -> Integer -> Integer
pure native (.^.) xor :: Integer -> Integer -> Integer
pure native complement not :: Integer -> Integer
-- miscellaneous
--- Returns the number of bits in the minimal two's-complement representation of this 'Integer', excluding a sign bit.
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 double doubleValue :: Integer -> Double
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 (.|.) "|" :: Long -> Long -> Long
--- Computes binary _exclusive or_ of two long integers. Uses the java @^@-operator.
pure native (.^.) "^" :: Long -> Long -> Long
--- Computes binary _and_ of two integers. Uses the java @&@-operator.
pure native (.&.) "&" :: Long -> Long -> Long
pure native shiftL "<<" :: Long -> Int -> Long
pure native shiftR ">>" :: Long -> Int -> Long
--- unsigned right shift
pure native ushiftR ">>>" :: Long -> Int -> Long
pure native complement "~" :: Long -> Long
--- Returns the value obtained by rotating the two's complement binary representation
--- of the specified long value left by the specified number of bits.
pure native rotateL java.lang.Long.rotateLeft :: Long -> Int -> Long
--- Returns the value obtained by rotating the two's complement binary representation
--- of the specified long value right by the specified number of bits.
pure native rotateR java.lang.Long.rotateRight :: Long -> Int -> Long
pure native size java.lang.Long.SIZE :: Int
--- hash code is upper half and lower half xor'ed
hashCode l = (int l) Int.`.^.` (int (l `shiftR` 32))
--- 'Char' values are based on Java's primitive @char@ values.
--- This type has many native functions based on the methods in @java.lang.Character@.
--- Most @is...@ functions work on 'Char' and 'Int' (codepoint).
--- Likewise, most @to...Case@ functions work on codepoints.
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
| Int -> Bool
--- The lowercase equivalent of the character, if any; otherwise, the character itself.
pure native toLowerCase java.lang.Character.toLowerCase :: Char -> Char
| Int -> Int
pure native isUpperCase java.lang.Character.isUpperCase :: Char -> Bool
| Int -> Bool
--- The uppercase equivalent of the character, if any; otherwise, the character itself.
pure native toUpperCase java.lang.Character.toUpperCase :: Char -> Char
| Int -> Int
--- The titlecase equivalent of the character, if any; otherwise, the character itself.
pure native toTitleCase java.lang.Character.toTitleCase :: Char -> Char
| Int -> Int
pure native isWhitespace java.lang.Character.isWhitespace :: Char -> Bool
| Int -> Bool
pure native isLetterOrDigit java.lang.Character.isLetterOrDigit :: Char -> Bool
| Int -> Bool
pure native isDigit java.lang.Character.isDigit :: Char -> Bool
| Int -> Bool
--- Returns the numeric value of the character argument in the specified radix.
--- If the character is not a digit in the given radix, -1 is returned.
--- The radix must be in the range 2..36, otherwise also -1 is returned.
pure native digit java.lang.Character.digit Char Int Int
--- > Char.forDigit d r
--- returns the character for the digit _d_ in radix _r_
--- _d_ must not be negative and lower than _r_, and _r_ must be in the range 2..36
--- When the arguments are invalid the character \'\u0000\' is returned.
pure native forDigit java.lang.Character.forDigit Int Int Char
pure native isLetter java.lang.Character.isLetter :: Char -> Bool
| Int -> Bool
{--
Determines if the specified character is an ISO control character.
A character is considered to be an ISO control character if its code is
in the range "\u0000" through "\u001F"
or in the range "\u007F" through "\u009F".
-}
pure native isISOControl java.lang.Character.isISOControl :: Char Bool
| Int Bool
{--
Determines if the given char value is a Unicode surrogate code unit.
Such values do not represent characters by themselves,
but are used in the representation of supplementary characters
in the UTF-16 encoding.
A char value is a surrogate code unit if and only if
it is either a low-surrogate code unit or a high-surrogate code unit.
-}
pure native isSurrogate java.lang.Character.isSurrogate Char Bool
{--
Determines if the given char value is a Unicode low-surrogate code unit
(also known as trailing-surrogate code unit).
Such values do not represent characters by themselves,
but are used in the representation of supplementary characters in the UTF-16 encoding.
-}
pure native isLowSurrogate java.lang.Character.isLowSurrogate Char Bool
{--
Determines if the given char value is a Unicode high-surrogate code unit
(also known as leading-surrogate code unit).
Such values do not represent characters by themselves,
but are used in the representation of supplementary characters in the UTF-16 encoding.
-}
pure native isHighSurrogate java.lang.Character.isHighSurrogate Char Bool
{--
Determines whether the specified character (Unicode code point)
is in the supplementary character range.
This is roughly equivalent to
> (> ord Char.maxBound)
except that it also checks if the value is lower than @0x110000@
If, for some integer @n@
> not (Char.isSupplementaryCodePoint n) && (n > ord Char.maxBound)
then @n@ is not a codepoint at all.
-}
pure native isSupplementaryCodePoint
java.lang.Character.isSupplementaryCodePoint :: Int -> Bool
--- Determines whether the specified code point is a valid Unicode code point value.
--- This is the case if it is not negative and lower than @0x110000@
pure native isValidCodePoint
java.lang.Character.isValidCodePoint :: Int -> Bool
{--
Determines if a character (Unicode code point) is defined in Unicode.
A character is defined if at least one of the following is true:
- It has an entry in the UnicodeData file.
- It has a value in a range defined by the UnicodeData file.
-}
pure native isDefined
java.lang.Character.isDefined :: Char -> Bool
| Int -> Bool
{--
The leading surrogate (which is a high surrogate code unit) of the
surrogate pair representing the specified supplementary character
(Unicode code point) in the UTF-16 encoding.
If the specified value is not a supplementary character,
an unspecified character is returned.
See also: 'Char.isSupplementaryCodePoint', 'Char.lowSurrogate', 'Char.toCodePoint'
The following holds:
> isSupplementaryCodePoint x ==> (x == toCodePoint (highSurrogate x) (lowSurrogate x))
-}
pure native highSurrogate java.lang.Character.highSurrogate :: Int -> Char
{--
The trailing surrogate (which is a low surrogate code unit) of the
surrogate pair representing the specified supplementary character
(Unicode code point) in the UTF-16 encoding.
If the specified value is not a supplementary character,
an unspecified character is returned.
See also: 'Char.isSupplementaryCodePoint', 'Char.highSurrogate', 'Char.toCodePoint'
The following holds:
> isSupplementaryCodePoint x ==> (x == toCodePoint (highSurrogate x) (lowSurrogate x))
-}
pure native lowSurrogate java.lang.Character.lowSurrogate :: Int -> Char
{--
> Char.toCodePoint high low
Converts the specified surrogate pair to its supplementary code point value.
This function does not validate the specified surrogate pair.
The caller must validate it using 'Char.isSurrogatePair' if necessary.
-}
pure native toCodePoint java.lang.Character.toCodePoint :: Char -> Char -> Int
{--
Determines whether the specified pair of char values is a valid Unicode surrogate pair.
-}
pure native isSurrogatePair java.lang.Character.isSurrogatePair :: Char -> Char -> Bool
{--
Returns a value indicating a character's general category.
-}
pure native getType java.lang.Character.getType Char Int
| Int Int
{--
Return the Unicode name of the code point or null if it is unassigned.
-}
pure native getName java.lang.Character.getName Char Maybe String
| Int Maybe String
{--
'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 'String.charAt' 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
{-- 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 caught 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 -> (NumberFormatException|Int)
--- Safe way to parse a long integer from a string. See 'String.int'
pure native long java.lang.Long.parseLong :: String -> (NumberFormatException|Long)
--- Safe way to parse a 'Float' value from a string. See 'String.int'
pure native float java.lang.Float.parseFloat :: String -> (NumberFormatException|Float)
--- Safe way to parse a 'Double' value from a string. See 'String.int'
pure native double java.lang.Double.parseDouble :: String -> (NumberFormatException|Double)
--- Safe way to parse a big 'Integer' value from a string. See 'String.int'
pure native integer new :: String -> (NumberFormatException|Integer)
--- retrieve character at index
pure native charAt :: String -> Int -> Char
--- > str.indexOf ch
--- the first index of _ch_ in _str_, or -1 if not present
pure native indexOf :: String -> Char -> Int
{-- Retrieve element of 'String' at index
Because it is impossible to create a 'String' from anything but 'Char's,
the type is not even wrong.
Will be needed in the 'String' instance of 'frege.prelude.PreludeList#ListLike'
that expects a type with kind @*->*@.
-}
pure native polymorphicElemAt charAt :: StringJ a -> Int -> a
-- Get character at index.
-- pure native frozenGetAt 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 hash code
pure native hashCode :: String -> Int
--- see 'substr'
pure native substr substring :: StringJ a -> Int -> Int -> StringJ a
--- true if the second string is a prefix of the first one
pure native startsWith :: String -> String -> Bool
--- convert an 'Int' to a 'String'
pure native intToString java.lang.String.valueOf :: Int -> String
--- Format 1 to 9 values
--- May throw @IllegalFormatException@, if the type of any argument does not fit the format specifier.
pure native format java.lang.String.format
:: String -> a -> String
| String -> a -> b -> String
| String -> a -> b -> c -> String
| String -> a -> b -> c -> d -> String
| String -> a -> b -> c -> d -> e -> String
| String -> a -> b -> c -> d -> e -> f -> String
| String -> a -> b -> c -> d -> e -> f -> g -> String
| String -> a -> b -> c -> d -> e -> f -> g -> h -> String
| String -> a -> b -> c -> d -> e -> f -> g -> h -> i -> String
--- wait on 'Object's monitor
native wait frege.runtime.Concurrent.waitFor :: String -> IO () throws InterruptedException
--- notify a single thread waiting on the objects monitor
native notify frege.runtime.Concurrent.notifyOne :: String -> IO ()
--- notify all threads waiting on the objects monitor
native notifyAll frege.runtime.Concurrent.notifyAll :: String -> IO ()
{--
@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
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 specified 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 'frege.prelude.Math#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
--- 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 specified 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 'frege.prelude.Math#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
--- 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
{--
The Java Object type
-}
protected data Object = pure native java.lang.Object where
--- for any value, we can get its @Java@ class
pure native getClass frege.runtime.Runtime.getClass :: a -> Class a
--- wait on 'Object's monitor
native wait frege.runtime.Concurrent.waitFor :: Object -> IO () throws
InterruptedException
--- notify a single thread waiting on the objects monitor
native notify frege.runtime.Concurrent.notifyOne :: Object -> IO ()
--- notify all threads waiting on the objects monitor
native notifyAll frege.runtime.Concurrent.notifyAll :: Object -> IO ()
protected data InterruptedException = pure native java.lang.InterruptedException
{-- warning: probably catches more exceptions than you want to handle, use (Exception1|Exception2|Result)
This is the principal return type for java methods that are expected to
throw exceptions.
It is strongly recommended to use more specific exception types.
-}
type CatchAll = Either Throwable
{--
* We need to do some reflection from frege code.
* For example, when we catch a 'Throwable' thrown from Java code.
* we might want to know what it is.
-}
data Class a = pure native java.lang.Class where
pure native getName :: Class a -> String
native forName java.lang.Class.forName
:: String -> IO (ClassNotFoundException|Class a)
--- Frege wrapper for java Throwables.
protected data Throwable = pure native java.lang.Throwable where
pure native getLocalizedMessage :: Throwable -> String
pure native getMessage :: Throwable -> String
native printStackTrace :: Throwable -> IO ()
--- give the class name of this exception
caught :: Throwable -> String
caught t = t.getClass.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);
--- @a `seq` b@ evaluates _a_ before it returns _b_
--- This is a right associative operator with precedence 15.
seq !a b = b
--######### undefined things ####################
--- An unchecked subclass of @java.lang.RuntimeException@ for the Frege Runtime
--- An instance of 'Undefined' will be thrown if 'undefined' or ('error' msg) is evaluated.
data Undefined = pure native frege.runtime.Undefined where
{--
create an 'Undefined' value with a message ('String')
or with a message and a cause. The cause is another
exception that caused this one.
-}
pure native new :: String -> Undefined
| String -> Throwable -> Undefined
{-- create an 'Undefined' value from a cause ('Throwable').
The message will be taken from the cause.
-}
newX :: Throwable -> Undefined
newX jex = new ((("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
--- A subclass of 'Undefined', used by the runtime to signal failed pattern matches
data NoMatch = pure native frege.runtime.NoMatch
--- A subclass of 'Undefined', used by the runtime to signal failed guards
data GuardFailed = pure native frege.runtime.GuardFailed
--- @java.lang.NumberFormatException@ needed for string conversion operations
--- declared *@protected@* to avoid name conflicts with 'frege.java.Lang#NumberFormatException'
protected data NumberFormatException = pure native java.lang.NumberFormatException
--- Forward declaration of 'frege.java.Lang#ClassNotFoundException'
protected data ClassNotFoundException
= pure native java.lang.ClassNotFoundException
--- This is the standard undefined value.
undefined :: u
undefined = error "undefined"
--- Construct an undefined value with an informative message.
--- When evaluated, an 'Undefined' exception will be thrown.
error :: String -> u
error s = if (Undefined.new s :: Undefined).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
--######### 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 ##################
--- 'Ordering' encodes the results of comparisons, see also '<=>'
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 Eq ord => 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'.
*
* Enumeration types have special syntactic support with the range list:
> [a .. b]
> [a ..]
> [a,b .. c]
> [a,b ..]
-}
class Ord e => Enum 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
--- used in translating @[n,n'..m]
enumFromThenTo :: e -> e -> e -> [e]
--- used in translating @[n,n'..]
enumFromThen :: e -> e -> [e]
--- used in translating @[n..m]
enumFromTo :: e -> e -> [e]
enumFromTo a b
| a < b = a:enumFromTo (succ a) b
| a == b = [a]
| otherwise = []
--- used in translating @[n..]
enumFrom :: e -> [e]
enumFrom a = enumFromThen a (succ a)
instance Eq () where
() != () = false
() == () = true
hashCode () = 42
--########### class Num - basic arithmetic ########################
{-- The 'Num' class provides the operators ('+'), ('-') and ('*') as well as
some functions that are common for all numeric types.
-}
class Ord n => Num 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
--- converts an 'Integer' value to the instantiated type
fromInteger :: Integer -> 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 functions 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 Num r => Real r where
--- the division operator
(/) :: r -> r -> r
--- convert a 'Double' to any 'Real' value
fromDouble :: Double -> 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
enumFromTo a b
| a < b = a:enumFromTo (succ a) b
| a == b = [a]
| otherwise = []
enumFrom !a = a : enumFrom (succ a)
enumFromThen !a !b = goFromBy a (b-a)
where
goFromBy :: Integer -> Integer -> [Integer]
goFromBy !a !inc = a : goFromBy (a+inc) inc
enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
then goFromByTo a (b-a) c
else []
where
goFromByTo !a inc c
| inc > 0n, a < c, (c-a) < inc = [a]
| a == c = [a]
| inc < 0n, a > c, (c-a) > inc = [a]
| otherwise = a : goFromByTo (a+inc) inc c
;
{--
* 'Integer' is an instance of 'Integral'
-}
instance Integral Integer where
fromInt i = Int.big i
fromInteger b = b -- identity
big b = b -- i am already big
even n = (n Integer.`.&.` one) == zero
odd n = (n Integer.`.&.` one) != zero
toInteger = Integral.big
--- Class 'Integral' provides division and remainder operations for integral numbers.
class Num integ => Integral 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
--- every integral number can be converted to a big 'Integer'
big :: integ -> Integer
--- every 'Num' can be made from an 'Integral'
fromIntegral :: Num b => integ -> b
fromIntegral i = fromInteger (big i)
-- -----------------------------------------------------
{--
'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, gcdHelper :: integ -> integ -> integ
gcd x y = gcdHelper (abs x) (abs y)
--- '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)
--- @ x ^ n @ raise _x_ to the _n_-th power
--- The exponent must be positive.
(^) :: Num a => a -> integ -> a
x0 ^ y0
| y0 < 0 = error "Negative exponent"
| y0 == 0 = 1
| otherwise = powf x0 y0
even, odd :: integ -> Bool
--- helper for 'Integral.^'
private powf :: Num a => a -> integ -> a
private powf x y
| even y = powf (x * x) (y `quot` 2)
| y == 1 = x
| otherwise = powg (x * x) ((y - 1) `quot` 2) x
--- helper for 'Integral.^'
private powg :: Num a => a -> integ -> a -> a
private powg x y z
| even y = powg (x * x) (y `quot` 2) z
| y == 1 = x * z
| otherwise = powg (x * x) ((y - 1) `quot` 2) (x * z)
--- worker function for 'Integral.gcd', needs not pollute the namespace
private gcdHelper !a !b
| b == zero = a
| otherwise = gcdHelper b (a `rem` b)
--############ Int instances & functions ############################
instance Eq Int where
--- Uses the java @==@ operator for comparison of 'Int' values.
pure native == :: Int -> Int -> Bool
--- Uses the java @!=@ operator for comparison of 'Int' values.
pure native != :: Int -> Int -> Bool
instance Ord Int where
--- Uses the java @<=@ operator for comparison of 'Int' values.
pure native <= :: Int -> Int -> Bool
--- Uses the java @>=@ operator for comparison of 'Int' values.
pure native >= :: Int -> Int -> Bool
--- Uses the java @<@ operator for comparison of 'Int' values.
pure native < :: Int -> Int -> Bool
--- Uses the java @>@ operator for comparison of 'Int' values.
pure native > :: Int -> Int -> Bool
(<=>) :: Int -> Int -> Ordering
(a) <=> (b) = if a<b then Lt else if a>b 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
fromInteger b = b.int
instance Eq Long where
--- Uses the java @==@ operator for comparison of 'Long' values.
pure native == :: Long -> Long -> Bool
--- Uses the java @!=@ operator for comparison of 'Long' values.
pure native != :: Long -> Long -> Bool
instance Ord Long where
--- Uses the java @<=@ operator for comparison of 'Long' values.
pure native <= :: Long -> Long -> Bool
--- Uses the java @>=@ operator for comparison of 'Long' values.
pure native >= :: Long -> Long -> Bool
--- Uses the java @<@ operator for comparison of 'Long' values.
pure native < :: Long -> Long -> Bool
--- Uses the java @>@ operator for comparison of 'Long' values.
pure native > :: Long -> Long -> Bool
(<=>) :: Long -> Long -> Ordering
(a) <=> (b) = if a<b then Lt else if a>b 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
--- applies the widening primitive conversion (JLS §5.1.2) from @int@ to @long@
fromInt i = i.long
fromInteger n = n.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"
enumFromTo a b
| a < b = a:enumFromTo (succ a) b
| a == b = [a]
| otherwise = []
enumFrom a = enumFromTo a maxBound
enumFromThen !a !b = enumFromThenTo a b (if a<b then maxBound else minBound)
enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
then goFromByTo a (b-a) c
else []
where
goFromByTo !a inc c
| inc > 0, a < c, (c-a) < inc = [a]
| a == c = [a]
| inc < 0, a > c, (c-a) > inc = [a]
| otherwise = a : goFromByTo (a+inc) inc c
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"
enumFromTo a b
| a < b = a:enumFromTo (succ a) b
| a == b = [a]
| otherwise = []
enumFrom a = enumFromTo a maxBound
enumFromThen !a !b = enumFromThenTo a b (if a<b then maxBound else minBound)
enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
then goFromByTo a (b-a) c
else []
where
goFromByTo !a inc c
| inc > 0L, a < c, (c-a) < inc = [a]
| a == c = [a]
| inc < 0L, a > c, (c-a) > inc = [a]
| otherwise = a : goFromByTo (a+inc) inc c
instance Integral Int where
pure native rem % :: Int -> Int -> Int
pure native quot / :: Int -> Int -> Int
even n = (n Int.`.&.` one) == zero
odd n = (n Int.`.&.` one) != zero
big l = Integer.valueOf l.long
instance Integral Long where
pure native rem % :: Long -> Long -> Long
pure native quot / :: Long -> Long -> Long
even n = (n Long.`.&.` one) == zero
odd n = (n Long.`.&.` one) != zero
big l = Integer.valueOf l
--############# 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"
enumFromTo a b = case a <=> b of
Lt -> [a,b]
Eq -> [a]
Gt -> []
enumFromThen a b
| a != b = [a,b]
| otherwise = []
enumFromThenTo a b _ = enumFromThen a b
enumFrom false = [false,true]
enumFrom true = [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)
enumFromTo a b
| a < b = a:enumFromTo (succ a) b
| a == b = [a]
| otherwise = []
enumFrom a = enumFromTo a maxBound
enumFromThen !a !b = enumFromThenTo a b (if a<b then maxBound else minBound)
enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
then goFromByTo (ord a) (ord b - ord a) (ord c)
else []
where
goFromByTo !a inc c
| inc > 0, a < c, (c-a) < inc = [Char.from a]
| a == c = [Char.from a]
| inc < 0, a > c, (c-a) > inc = [Char.from a]
| otherwise = Char.from a : goFromByTo (a+inc) inc c
chr i = Char.from i
--- make a 'String' from a single 'Char'
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 a<b then Lt else if a>b 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
fromInteger n = n.double.float
fromDouble d = d.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 a<b then Lt else if a>b 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
fromInteger n = n.double
fromDouble d = d
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 a => Eq [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
--- apply first function to value in 'Left' or second function to value in 'Right'
either left right (Left x) = left x
either left right (Right x) = right x
--- return the first element of a 2-tuple
fst (a, _) = a
--- return the second element of a 2-tuple
snd (_, a) = a
--- A head strict variant of (:)
--- This will be used in list comprehensions
!x !: xs = x:xs
{- more tuple stuff in Tuples.fr -}
-- function stuff
protected id x = x -- despite Category, do not remove, it is used in code generation
{--
@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, because '$' 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
--- @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)
--- 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 '=='.
* Example usage:
* > 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 projection 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 #################################
-- ####################################################################
--- > g `on` f
--- Apply a projection function @f@ on both operands of @g@
--- > comparing f = (<=>) `on` f
g `on` f = \a\b -> f a `g` f b
{--
* @(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 independent 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 shall be wrapped in a 'frege.prelude.PreludeIO#Mutable'
* with phantom type parameter @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 :: Long -> ST s (Mutable s Date)
* 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 'frege.prelude.PreludeMonad#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 :: Mutable s Date -> ST s String
* and a computation which yields the current time in string form:
* > epoch = do
* > date <- Date.new 0L
* > return date.toString
* This looks almost like java already! @epoch@ has type @ST s String@ and we can run
* the computation with @epoch.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 'ST.run' an 'IO' action.
-}
public run :: forall a . (forall ß. ST ß a) -> a
public run stx = (stx.app "stateful")
--- warning: You are breaking the rules. Expect an arbitrary result and program crashes.
public performUnsafe (ST x) = (x RealWorld.rw)
-- 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.
-}
data RealWorld = pure native frege.runtime.Phantom.RealWorld where
private pure native rw frege.runtime.Phantom.theRealWorld :: RealWorld
--- @IO a@ is an abbreviation for 'ST' 'RealWorld' @a@
type IO = ST RealWorld
--- warning: use @stderr.print@ instead
--- print a 'String' to the standard error stream
native traceStr java.lang.System.err.print :: String -> IO ()
--- warning: use @stderr.println@ instead
--- print a 'String' to the standard error stream and append a new line.
native traceStrLn java.lang.System.err.println :: String -> IO ()
--- warning: use @stdout.print@ instead
--- print a 'String' to the standard output stream
native printStr java.lang.System.out.print :: String -> IO ()
--- warning: use @stdout.println@ instead
--- print a 'String' to the standard output stream and append a new line.
native printStrLn java.lang.System.out.println :: String -> IO ()
Jump to Line
Something went wrong with that request. Please try again.