X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.runtime%2Fscl%2FPrelude.scl;h=eb8026de910e15f2b8900c2e0fce6a6d6a0d0d6e;hp=f0eca0eb26dc78141f4a4f204f9f46ce14948c2c;hb=e9757cdfe5996d87738cabad84bff0343f56e4e3;hpb=074cf59788feedea1837d60b133142dd73c43058 diff --git a/bundles/org.simantics.scl.runtime/scl/Prelude.scl b/bundles/org.simantics.scl.runtime/scl/Prelude.scl index f0eca0eb2..eb8026de9 100644 --- a/bundles/org.simantics.scl.runtime/scl/Prelude.scl +++ b/bundles/org.simantics.scl.runtime/scl/Prelude.scl @@ -74,7 +74,7 @@ infixl 5 (\\), (<<), (<+) infix 4 (!=), (<), (<=), (>=), (>) infixr 3 (&&), (&<&) infixr 2 (||), orElse, morelse -infixr 1 (>>=), (>>), (:=) +infixr 1 (>>=), (>>), (:=), (>=>) infixr 1 ($) infixl 1 catch @@ -123,6 +123,7 @@ uncurry3 f (x, y, z) = f x y z flip :: (a -> b -> c) -> b -> a -> 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) @@ -920,6 +921,10 @@ Sequentially compose two actions, discarding any value produced by the first, li (>>) :: 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 :: ( Boolean) -> ( a) -> () @@ -1065,15 +1070,40 @@ mapEither f list = runProc do 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 -> m b) -> f a -> 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 -> m b) -> 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." @@ -1132,6 +1162,14 @@ class IndexedSequence f where "`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 @@ -1408,6 +1446,17 @@ instance Read String where 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 @@ -1435,6 +1484,14 @@ fst (x,y) = x snd :: (a,b) -> b snd (x,y) = y +@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 @@ -1542,12 +1599,25 @@ printWithSeparator sb sep l = loop 0 (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 @@ -1876,14 +1946,51 @@ importJava "org.simantics.scl.runtime.Lists" where "Sorts the list using the given comparator." sortWith :: (a -> a -> Integer) -> [a] -> [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 -> b) -> [a] -> (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 -> b) -> [a] -> [(b, [a])] + + "Groups a list of key-value pairs by the keys." + group :: [(a,b)] -> [(a, [b])] + + "Composition of index and groupBy." + indexGroupBy :: (a -> b) -> [a] -> (b -> [a]) + + "Composition of index and group." + indexGroup :: [(a,b)] -> a -> [b] + groupWith :: (b -> Integer) -> (b -> b -> Boolean) -> (a -> b) -> (a -> c) -> [a] -> [(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 -> a) -> a) -> [b] @@ -1904,6 +2011,16 @@ 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. """ @@ -2008,42 +2125,9 @@ sortBy f l = sortWith (\x y -> compare (f x) (f y)) l // 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 :: [(a,b)] -> a -> Maybe b -index = indexWith hashCode (==) - -""" -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 -> 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 :: (a -> b) -> [a] -> [(b, [a])] -groupBy f l = groupWith hashCode (==) f id l - -"Groups a list of key-value pairs by the keys." -group :: [(a,b)] -> [(a, [b])] -group = groupWith hashCode (==) fst snd - -"Removes duplicates (all but the first occurrence) from the list but otherwise preserves the order of the elements." -unique :: [a] -> [a] -unique = uniqueWith (==) - -"Like `unique`, but uses the given function for finding the key values used for uniqueness testing." -uniqueBy :: (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`." (\\) :: [a] -> [a] -> [a] -(\\) = deleteAllBy (==) +(\\) = listDifference /// Dynamic /// @@ -2130,6 +2214,12 @@ importJava "java.lang.Throwable" where @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 @@ -2141,6 +2231,20 @@ instance Show Throwable where 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 -> ()