binding :: Serializable a => Binding a
***********************************************************/
+type BooleanArray = Vector Boolean
+type ByteArray = Vector Byte
+type CharacterArray = Vector Character
+type ShortArray = Vector Short
+type IntegerArray = Vector Integer
+type LongArray = Vector Long
+type FloatArray = Vector Float
+type DoubleArray = Vector Double
+
importJava "java.util.Arrays" where
- @private
- @JavaName equals
- equalsDoubleArray :: DoubleArray -> DoubleArray -> Boolean
-
- @private
- @JavaName toString
- showDoubleArray :: DoubleArray -> String
-
"Converts an array to a list."
@JavaName asList
arrayToList :: Array a -> [a]
@JavaName toArray
listToArray :: [a] -> Array a
-instance Eq DoubleArray where
- (==) = equalsDoubleArray
-instance Show DoubleArray where
- show = showDoubleArray
-
importJava "org.simantics.scl.runtime.Coercion" where
"Converts a list of doubles to a double array."
toDoubleArray :: [Double] -> DoubleArray
infixl 7 (*), (/), div, mod
infixl 6 (+), (-)
infixl 5 (\\), (<<), (<+)
-infix 4 (==), (!=), (<), (<=), (>=), (>)
+infix 4 (!=), (<), (<=), (>=), (>)
infixr 3 (&&), (&<&)
infixr 2 (||), orElse, morelse
-infixr 1 (>>=), (>>), (:=)
+infixr 1 (>>=), (>>), (:=), (>=>)
infixr 1 ($)
infixl 1 catch
flip :: (a -> b -> <e> c) -> b -> a -> <e> c
flip f x y = f y x
+"Swaps the order of elements of a pair (2-tuple)."
swap :: (a,b) -> (b,a)
swap (x,y) = (y,x)
/// Comparison ///
-"""
-The class of types whose elements can be compared for equality.
-Method `(==)` must be implemented in instances.
-"""
-class Eq a where
- "Equality"
- (==) :: a -> a -> Boolean
- "Inequality: `a != b = not (a == b)`"
- (!=) :: a -> a -> Boolean
-
- a != b = not (a == b)
+@inline
+(!=) :: a -> a -> Boolean
+a != b = not (a == b)
"""
The class of linearly ordered types.
Method `compare` must be implemented in instances.
"""
-class (Eq a) => Ord a where
+class Ord a where
"""
`compare x y` returns a negative number, if `x` is smaller than `y`,
a positive number, if `x` is bigger than `y` and zero if they are equal.
where
minF a b = if fst a <= fst b then a else b
-"""
-The class of types with method to compute hash codes.
-"""
-class (Eq a) => Hashable a where
- "`hashP v seed` computes the hash code of `v` using `seed` as a seed."
- hashP :: a -> Integer -> Integer
-
-"`hash v` computes the hash code of `v`"
-hash :: Hashable a => a -> Integer
-hash a = hashP a 1166136261
-
/// Functions ///
/*
instance Functor ((->) a) where
@JavaName parseByte
readByte :: String -> Byte
-instance Eq Byte where
- (==) = Java.bcmpeq
- (!=) = Java.bcmpne
-
instance Ord Byte where
(<) = Java.bcmplt
(<=) = Java.bcmple
@JavaName parseShort
readShort :: String -> Short
-instance Eq Short where
- (==) = Java.scmpeq
- (!=) = Java.scmpne
-
instance Ord Short where
(<) = Java.scmplt
(<=) = Java.scmple
@JavaName parseInt
readInteger :: String -> Integer
-instance Eq Integer where
- (==) = Java.icmpeq
- (!=) = Java.icmpne
-
instance Ord Integer where
(<) = Java.icmplt
(<=) = Java.icmple
(>) = Java.icmpgt
(>=) = Java.icmpge
-
-instance Hashable Integer where
- hashP v x = Java.ixor v (Java.imul x 16777619) // prime for FNV-1 hash
instance Additive Integer where
zero = Java.iconst_0
@JavaName parseLong
readLong :: String -> Long
-instance Eq Long where
- (==) = Java.lcmpeq
- (!=) = Java.lcmpne
-
instance Ord Long where
(<) = Java.lcmplt
(<=) = Java.lcmple
(>) = Java.lcmpgt
(>=) = Java.lcmpge
-
-instance Hashable Long where
- hashP v x = Java.l2i (Java.lxor v (Java.lushr v 32)) + x*16777619
instance Additive Long where
zero = Java.lconst_0
"Converts 32-bit floating point number to a 32-bit integer with the same byte level representation."
floatToIntBits :: Float -> Integer
-instance Eq Float where
- (==) = Java.fcmpeq
- (!=) = Java.fcmpne
-
instance Ord Float where
compare = compareFloat
(<) = Java.fcmplt
(>) = Java.fcmpgt
(>=) = Java.fcmpge
-instance Hashable Float where
- hashP v x = hashP (floatToIntBits v) x
-
instance Additive Float where
zero = Java.fconst_0
(+) = Java.fadd
isNaN :: Double -> Boolean
isInfinite :: Double -> Boolean
-instance Eq Double where
- (==) = Java.dcmpeq
- (!=) = Java.dcmpne
-
instance Ord Double where
compare = compareDouble
(<) = Java.dcmplt
(<=) = Java.dcmple
(>) = Java.dcmpgt
- (>=) = Java.dcmpge
-
-instance Hashable Double where
- hashP v x = hashP (doubleToLongBits v) x
+ (>=) = Java.dcmpge
instance Additive Double where
zero = Java.dconst_0
"Returns true, if the given character is a digit."
isDigit :: Character -> Boolean
-instance Eq Character where
- (==) = Java.ccmpeq
- (!=) = Java.ccmpne
-
instance Ord Character where
(<) = Java.ccmplt
(<=) = Java.ccmple
(>>) :: Monad m => m a -> m b -> m b
a >> b = a >>= (\_ -> b)
+"Left-to-right Kleisli composition of monads."
+(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
+(f >=> g) x = (f x) >>= g
+
"While loop. `while cond body` executes the `body` while the `cond` is true."
@inline
while :: (<e> Boolean) -> (<e> a) -> <e> ()
Right v -> addArrayList r v)
(Java.unsafeCoerce l, Java.unsafeCoerce r)
+"`replicate n v` returns a list of length `n` such that each element is a copy of `v`."
+@inline
+replicate :: Integer -> a -> [a]
+replicate n v = build (\empty cons ->
+ let aux 0 l = l
+ aux i l = aux (i-1) (cons l v)
+ in aux n empty
+ )
+
/// FunctorM ///
-class (Functor f) => FunctorM f where
+class (FunctorE f) => FunctorM f where
"`mapM f` is equivalent to `sequence . map f`."
- mapM :: Monad m => (a -> m b) -> f a -> m (f b)
+ mapM :: Monad m => (a -> <e> m b) -> f a -> <e> m (f b)
"Evaluate each action in the sequence from left to right, and collect the results."
sequence :: Monad m => f (m a) -> m (f a)
- mapM f l = sequence (fmap f l)
+ mapM f l = sequence (map f l)
+
+/// MonadE ///
+class (FunctorE m, Monad m) => MonadE m where
+ bindE :: m a -> (a -> <e> m b) -> <e> m b
+
+instance MonadE Maybe where
+ bindE Nothing _ = Nothing
+ bindE (Just v) f = f v
+
+instance MonadE (Either a) where
+ bindE (Left v) _ = Left v
+ bindE (Right v) f = f v
+
+instance MonadE [] where
+ bindE l f = concatMap f l
+
/// Category ///
"Identity function."
"`seq ! i` returns the `i`th element of the sequence `seq`. Indexing starts from zero."
(!) :: f a -> Integer -> a
+"Returns the first element of a sequence"
+@inline
+first l = l!0
+
+"Returns the last element of a sequence"
+@inline
+last l = l!(length l-1)
+
instance IndexedSequence [] where
(!) = getList
otherwise :: Boolean
otherwise = True
-instance Eq Boolean where
- a == b = if a then b else not b
- a != b = if a then not b else b
-
instance Ord Boolean where
compare False False = 0
compare False True = neg 1
fromJust :: Maybe a -> a
fromJust (Just a) = a
-deriving instance (Eq a) => Eq (Maybe a)
deriving instance (Ord a) => Ord (Maybe a)
deriving instance (Show a) => Show (Maybe a)
-deriving instance (Hashable a) => Hashable (Maybe a)
instance Functor Maybe where
fmap _ Nothing = Nothing
orElse (Just x) _ = x
orElse Nothing def = def
+@inline
+orElseM :: Maybe a -> (<e> Maybe a) -> <e> Maybe a
+orElseM mx@(Just x) _ = mx
+orElseM Nothing def = def
+
/// Either ///
"""
The `Either` type is sometimes used to represent a value which is either correct or an error; by convention, the `Left` constructor
is used to hold an error value and the `Right` constructor is used to hold a correct value (mnemonic: "right" also means "correct").
"""
-data Either a b = Left a | Right b
+@JavaType "org.simantics.scl.runtime.either.Either"
+data Either a b =
+ @JavaType "org.simantics.scl.runtime.either.Left"
+ @FieldNames [value]
+ Left a
+ | @JavaType "org.simantics.scl.runtime.either.Right"
+ @FieldNames [value]
+ Right b
-deriving instance (Eq a, Eq b) => Eq (Either a b)
deriving instance (Ord a, Ord b) => Ord (Either a b)
deriving instance (Show a, Show b) => Show (Either a b)
-deriving instance (Hashable a, Hashable b) => Hashable (Either a b)
instance Functor (Either a) where
fmap _ (Left x) = Left x
@JavaName "compareTo"
compareString :: String -> String -> Integer
@private
-// @JavaName "hashCode"
-// hashString :: String -> Integer
- @private
- @JavaName "equals"
- equalsString :: String -> String -> Boolean
- @private
@JavaName "length"
lengthString :: String -> Integer
"Creates a string from a vector of characters."
@JavaName "<init>"
string :: Vector Character -> String
-
-instance Eq String where
- (==) = equalsString
-instance Hashable String where
- hashP x v = Java.hashCode x + v*16777619
+ getBytes :: String -> String -> ByteArray
+
+getBytesUTF8 :: String -> ByteArray
+getBytesUTF8 str = getBytes str "UTF-8"
instance Ord String where
compare = compareString
instance Read String where
read str = str
+@deprecated "Instead of 'splitString text pattern', write 'split pattern text' (note change in the parameter order)."
"`splitString text pattern` splits the string into a list of string where the parts are sepratated in the original list by the given pattern."
splitString :: String -> String -> [String]
splitString source pattern = arrayToList $ splitString_ source pattern
+"""
+`split pattern text` splits `text` around matches of the given regular expression `pattern`.
+
+This function works as if by invoking the two-argument split method with the given expression and a limit argument of zero. Trailing empty strings are therefore not included in the resulting array.
+
+The string "boo:and:foo", for example, yields the following results with these expressions:
+
+ Regex Result
+ : { "boo", "and", "foo" }
+ o { "b", "", ":and:f" }
+"""
split :: String -> String -> [String]
split pattern text = arrayToList $ splitString_ text pattern
/// Tuple0 ///
-instance Eq () where
- () == () = True
-
instance Ord () where
compare () () = 0
-instance Hashable () where
- hashP () x = x
-
instance Additive () where
zero = ()
() + () = ()
snd :: (a,b) -> b
snd (x,y) = y
-instance (Eq a, Eq b) => Eq (a, b) where
- (a0, b0) == (a1, b1) = a0 == a1 && b0 == b1
+@inline
+mapFst :: (a -> b) -> (a,c) -> (b,c)
+mapFst f (x,y) = (f x, y)
+
+@inline
+mapSnd :: (a -> b) -> (c,a) -> (c,b)
+mapSnd f (x,y) = (x, f y)
instance (Ord a, Ord b) => Ord (a, b) where
compare (a0, b0) (a1, b1) = compare a0 a1 &<& compare b0 b1
-instance (Hashable a, Hashable b) => Hashable (a, b) where
- hashP (a,b) x = hashP b $ hashP a x
-
instance (Additive a, Additive b) => Additive (a, b) where
zero = (zero, zero)
(a0, b0) + (a1, b1) = (a0+a1, b0+b1)
/// Tuple3 ///
-instance (Eq a, Eq b, Eq c) => Eq (a, b, c) where
- (a0, b0, c0) == (a1, b1, c1) = a0 == a1 && b0 == b1 && c0 == c1
-
instance (Ord a, Ord b, Ord c) => Ord (a, b, c) where
compare (a0, b0, c0) (a1, b1, c1) = compare a0 a1 &<& compare b0 b1 &<& compare c0 c1
-instance (Hashable a, Hashable b, Hashable c) => Hashable (a, b, c) where
- hashP (a,b,c) x = hashP c $ hashP b $ hashP a x
-
instance (Additive a, Additive b, Additive c) => Additive (a, b, c) where
zero = (zero, zero, zero)
(a0, b0, c0) + (a1, b1, c1) = (a0+a1, b0+b1, c0+c1)
/// Tuple4 ///
-instance (Eq a, Eq b, Eq c, Eq d) => Eq (a, b, c, d) where
- (a0, b0, c0, d0) == (a1, b1, c1, d1) = a0 == a1 && b0 == b1 && c0 == c1 && d0 == d1
-
instance (Ord a, Ord b, Ord c, Ord d) => Ord (a, b, c, d) where
compare (a0, b0, c0, d0) (a1, b1, c1, d1) =
compare a0 a1 &<& compare b0 b1 &<& compare c0 c1 &<& compare d0 d1
-instance (Hashable a, Hashable b, Hashable c, Hashable d) => Hashable (a, b, c, d) where
- hashP (a,b,c,d) x = hashP d $ hashP c $ hashP b $ hashP a x
-
instance (Additive a, Additive b, Additive c, Additive d) => Additive (a, b, c, d) where
zero = (zero, zero, zero, zero)
(a0, b0, c0, d0) + (a1, b1, c1, d1) = (a0+a1, b0+b1, c0+c1, d0+d1)
/// Tuple5 ///
-instance (Eq a, Eq b, Eq c, Eq d, Eq e) => Eq (a, b, c, d, e) where
- (a0, b0, c0, d0, e0) == (a1, b1, c1, d1, e1) =
- a0 == a1 && b0 == b1 && c0 == c1 && d0 == d1 && e0 == e1
-
instance (Ord a, Ord b, Ord c, Ord d, Ord e) => Ord (a, b, c, d, e) where
compare (a0, b0, c0, d0, e0) (a1, b1, c1, d1, e1) =
compare a0 a1 &<& compare b0 b1 &<& compare c0 c1 &<& compare d0 d1 &<& compare e0 e1
-
-instance (Hashable a, Hashable b, Hashable c, Hashable d, Hashable e)
- => Hashable (a, b, c, d, e) where
- hashP (a,b,c,d,e) x = hashP e $ hashP d $ hashP c $ hashP b $ hashP a x
instance (Additive a, Additive b, Additive c, Additive d, Additive e) => Additive (a, b, c, d, e) where
zero = (zero, zero, zero, zero, zero)
/// Lists ///
-instance (Eq a) => Eq [a] where
- a == b = lA == lB && loop 0
- where
- lA = length a
- lB = length b
- loop i = i>=lA || (a!i == b!i && loop (i+1))
-
instance (Ord a) => Ord [a] where
compare a b = loop 0
where
then 1
else compare (a!i) (b!i) &<& loop (i+1)
-instance (Hashable a) => Hashable [a] where
- hashP a x = loop 0 x
- where
- lA = length a
- loop i x = if i == lA
- then x
- else loop (i+1) (hashP (a!i) x)
-
instance Functor [] where
fmap = mapList
(if i==0 then sb else sb << sep) <+ l!i
loop (i+1)
-"Joins the string representations of the list of values with the given separator."
+"""
+Joins the string representations of the list of values with the given separator.
+
+See [intercalate](#intercalate) for an alternative that works with Strings
+and doesn't escape its arguments.
+"""
joinWithSeparator :: Show a => String -> [a] -> String
joinWithSeparator separator values = runProc (
StringBuilder.toString $ printWithSeparator StringBuilder.new separator values)
+
+"""
+The intercalate function takes a String and a list of Strings
+and concatenates the list after interspersing the first argument
+between each element of the list.
+
+See also more generic [joinWithSeparator](#joinWithSeparator)
+which escapes its arguments using `show`.
+"""
+intercalate :: String -> [String] -> String
+intercalate separator strings = do
+ l = length strings
+ if l == 0
+ then ""
+ else if l == 1
+ then strings!0
+ else runProc do
+ sb = StringBuilder.new
+ sb << strings!0
+ loop i | i == l = ()
+ | otherwise = do
+ sb << separator << strings!i
+ loop (i+1)
+ loop 1
+ StringBuilder.toString sb
+
instance (Show a) => Show [a] where
sb <+ l = do
len = length l
maybeToList (Just a) = [a]
maybeToList _ = []
+"""
+`takeWhile p l`, returns the longest prefix (possibly empty) of list `l` of elements that satisfy `p`
+"""
+takeWhile :: (a -> <e> Boolean) -> [a] -> <e> [a]
+takeWhile f l = loop 0
+ where
+ len = length l
+ loop i | i == len = l
+ | f (l!i) = loop (i+1)
+ | otherwise = take i l
+
partition :: (a -> <e> Boolean) -> [a] -> <e> ([a], [a])
partition p l = runProc do
res1 = newArrayList
"Sorts the list using the given comparator."
sortWith :: (a -> a -> <e> Integer) -> [a] -> <e> [a]
+
+ """
+ Given a list of key-value pairs, the function produces a function that finds a value
+ efficiently for the given key.
+ """
+ index :: [(a,b)] -> a -> Maybe b
+
+ """
+ Given a list of values and a function computing a key for each value, the function produces a function that finds a value
+ effeciently for the given key.
+ """
+ indexBy :: (a -> <e> b) -> [a] -> <e> (b -> Maybe a)
+
"Works like `index` but uses the given functions as hash codes and equality."
indexWith :: (a -> Integer) -> (a -> a -> Boolean) -> [(a,b)] -> a -> Maybe b
+
+ "Groups a list values by a key computed by the given function."
+ groupBy :: (a -> <e> b) -> [a] -> <e> [(b, [a])]
+
+ "Groups a list of key-value pairs by the keys."
+ group :: [(a,b)] -> [(a, [b])]
+
+ "Composition of index and groupBy."
+ indexGroupBy :: (a -> <e> b) -> [a] -> <e> (b -> [a])
+
+ "Composition of index and group."
+ indexGroup :: [(a,b)] -> a -> [b]
+
groupWith :: (b -> Integer) -> (b -> b -> Boolean) -> (a -> <e> b) -> (a -> <e> c) -> [a] -> <e> [(b, [c])]
+
+ "Removes duplicates (all but the first occurrence) from the list but otherwise preserves the order of the elements."
+ unique :: [a] -> [a]
+
+ "Like `unique`, but uses the given function for finding the key values used for uniqueness testing."
+ uniqueBy :: (a -> b) -> [a] -> [a]
+
"Works like `unique` but uses the given function for equality tests."
uniqueWith :: (a -> a -> Boolean) -> [a] -> [a]
+
"Works like `\\\\` but uses the given function for equality tests."
deleteAllBy :: (a -> a -> Boolean) -> [a] -> [a] -> [a]
+ @private
+ listDifference :: [a] -> [a] -> [a]
+
//range :: Integer -> Integer -> [Integer]
//build :: (forall a. a -> (a -> b -> <e> a) -> <e> a) -> <e> [b]
"`elem el lst` return true, if `el` occurs in the list `lst`."
-elem :: Eq a => a -> [a] -> Boolean
+elem :: a -> [a] -> Boolean
elem el l = loop 0
where
len = length l
| otherwise = False
"`elemMaybe v1 (Just v2)` returns true if `v1 == v2`. `elemMaybe v1 Nothing` is always false."
-elemMaybe :: Eq a => a -> Maybe a -> Boolean
+elemMaybe :: a -> Maybe a -> Boolean
elemMaybe el m = match m with
Just el2 -> el == el2
Nothing -> False
+"`elemIndex el lst` returns the index of the first element in the given list `lst` which is equal (by ==) to the query element, or Nothing if there is no such element."
+elemIndex :: a -> [a] -> Maybe Integer
+elemIndex el l = loop 0
+ where
+ len = length l
+ loop i | i < len = if el == l!i
+ then Just i
+ else loop (i+1)
+ | otherwise = Nothing
+
"""
Computes a list that contains only elements that belongs to both input lists.
"""
-intersect :: Eq a => [a] -> [a] -> [a]
+intersect :: [a] -> [a] -> [a]
intersect a b = filter f a
where
f e = elem e b
len = length l
"Tries to find the given key from the list of key-value pairs and returns the corresponding value."
-lookup :: Eq a => a -> [(a, b)] -> Maybe b
+lookup :: a -> [(a, b)] -> Maybe b
lookup el l = do
len = length l
loop i = if i < len
// This is faster if f is slow, but will generate more auxiliary structures
//sortBy f l = map snd (sortWith (\(x,_) (y,_) -> compare x y) [(f x, x) | x <- l])
-"""
-Given a list of key-value pairs, the function produces a function that finds a value
-efficiently for the given key.
-"""
-index :: Hashable a => [(a,b)] -> a -> Maybe b
-index = indexWith hash (==)
-
-"""
-Given a list of values and a function computing a key for each value, the function produces a function that finds a value
-effeciently for the given key.
-"""
-indexBy :: Hashable b => (a -> b) -> [a] -> b -> Maybe a
-indexBy f l = index [(f x, x) | x <- l]
-
-"Groups a list values by a key computed by the given function."
-groupBy :: Hashable b => (a -> <e> b) -> [a] -> <e> [(b, [a])]
-groupBy f l = groupWith hash (==) f id l
-
-"Groups a list of key-value pairs by the keys."
-group :: Hashable a => [(a,b)] -> [(a, [b])]
-group = groupWith hash (==) fst snd
-
-"Removes duplicates (all but the first occurrence) from the list but otherwise preserves the order of the elements."
-unique :: Eq a => [a] -> [a]
-unique = uniqueWith (==)
-
-"Like `unique`, but uses the given function for finding the key values used for uniqueness testing."
-uniqueBy :: Eq b => (a -> b) -> [a] -> [a]
-uniqueBy f = uniqueWith (\a b -> f a == f b)
-
-//sortAndUniqueBy :: Ord b => (a -> b) -> [a] -> [a]
-//sortAndUniqueBy f = map snd . uniqueWith (\a b -> fst a == fst b) . sortBy fst . map (\x -> (f x, x))
-
"`a \\\\ b` removes all elements of `b` from the list `a`."
-(\\) :: Eq a => [a] -> [a] -> [a]
-(\\) = deleteAllBy (==)
+(\\) :: [a] -> [a] -> [a]
+(\\) = listDifference
/// Dynamic ///
"Executes the given expression and catches certain class of exceptions (specified by the catch handler that is given as a second parameter.)"
@JavaName catch_
- catch :: VecComp ex => (<e> a) -> (ex -> <e> a) -> <e> a
+ catch :: VecComp ex => (<e,Exception> a) -> (ex -> <e> a) -> <e> a
importJava "java.lang.Throwable" where
data Throwable
@private
@JavaName toString
showThrowable :: Throwable -> String
+ @private
+ @JavaName getMessage
+ getMessageThrowable :: Throwable -> String
+ @private
+ @JavaName getCause
+ getCauseThrowable :: Throwable -> Maybe Throwable
importJava "java.lang.Exception" where
data Exception
@private
instance Show Exception where
show = showException
+class Throwable e where
+ toThrowable :: e -> Throwable
+
+messageOfException :: Throwable e => e -> String
+messageOfException = getMessageThrowable . toThrowable
+
+causeOfException :: Throwable e => e -> Maybe Throwable
+causeOfException = getCauseThrowable . toThrowable
+
+instance Throwable Throwable where
+ toThrowable = id
+instance Throwable Exception where
+ toThrowable = Java.unsafeCoerce
+
"Prints the given value in the console."
@inline
print :: Show a => a -> <Proc> ()