Commit ab4ee655 authored by Mart Lubbers's avatar Mart Lubbers

Merge branch 'master' of gitlab.science.ru.nl:clean-and-itasks/clean-platform...

Merge branch 'master' of gitlab.science.ru.nl:clean-and-itasks/clean-platform into _arjan/clean-platform-android
parents 5404aa8b 77b02c8b
test:
before_script:
- install_clean.sh bundle-complete && apt-get update -qq && apt-get install -y -qq build-essential
image: "camilstaps/clean:nightly"
script:
- make -C tests/linux64
# Standards
The following guidelines should be adhered to when developing libraries for the
Clean Platform library collection.
## What is the purpose of Clean Platform
Clean Platform was created to have a central place where commonly used
functionality was stored so that people didn't have to look for it. All the
functionality should be available on all platforms. This means that
functionality only working on Windows has no place here. It is allowed to
simulate functionality across systems. Examples of this is the System.Process
module that offers the same API across platforms.
## Type names
The names of types should be clear and informative, and should always start
with a capital. If the name of a type consists of multiple words, each new
word should start with a capital. Whenever the name is an abbreviation the
abbreviation should be written using only capitals (e.g. GUI,SQL,HTTP).
## Function names
Function names should be written in lowerCamelCase. By starting types and
constructors with a capital and functions without one, the difference between
a constructor and a function is immediately clear for the reader of a program.
## Module names
For modules, the same guidelines apply as for naming types. Names should be
informative and preferably short. When a library module is not meant for direct
imports by end users, but should only used by experts in modules that for
example provide a more friendly interface, you should prefix the name of that
module with an underscore character (`_`) or place it in a separate `Internal`
submodule.
## Argument order
While there are no hard demands on the order in which you specify the arguments
of functions, there are two rules which make your functions easier to use and
somewhat more clear:
- State representing arguments such as the common `*World` type argument,
should be at the end of the argument list.
- Arguments which are used as "options" in some way should be at the beginning
of the arguments. This makes it easy to pass in options by currying.
## Comments
A concise description of the purpose of a function and the meaning of its
arguments and result should be present in the .dcl file for all exported
functions. The documentation should not be included in the .icl file for
maintainability. Comments are specified as follows:
```clean
/**
* This function is the identity.
* @param Some value
* @result The same value
*/
id :: a -> a
id x = x
```
Several JavaDoc like parameters are supported such as `@param`, `@result`,
`@type`, `@var` and `@representation`. More info about this can be found
[here](https://github.com/clean-cloogle/Cloogle#clean-documentation).
We use `@complexity` for the complexity order. Some other special fields are
used, like `@gin-icon`, but one should be reluctant with inventing new field
names. If there is a general use case, adding it can be discussed.
## Layout
- Tabs should be used for indentation. Spaces for alignment.
- The `where` keyword should be at the same level as the parent code block.
## Exporting functions and types
Definition modules (.dcl) must be very specific about the modules they import
because everything imported in a definition module is exported as well,
increasing the chance of name collisions. To minimize the chance for
collisions, adhere to the following conventions:
- Explicitly import the types and classes you need for specifying the type
signatures by using the `from ... import ...` notation.
- Only ever import an entire module with the `import ...` notation if you
really truly want to re-export the entire module.
Implementation modules may import anything they like.
## Implementing class instances and generic derives
The applicable instances for the _general_ classes should be exported in the module of the type and not of the class.
This means that for example the `Functor` instance of `Maybe` should be defined in `Data.Maybe` and not in `Data.Functor`.
For _specific_ classes the instances for types should be exported in submodules.
For example, `JSONEncode` for `Map` should be exported in `Data.Map.JSONEncode` and not in `Data.Map` nor in `Text.JSON`.
This rule also holds for types that have multiple valid instances such as the `Monoid` for `Int`.
_general_ classes are:
- [ ] `Functor` from `Data.Functor`
- [ ] `Monoid, Semigroup` from `Data.Monoid`
- [ ] `Monad` from `Control.Monad` and applicable monads from `Control.Monad.*`
- [ ] `Applicative, Alternative` from `Control.Applicative`
- [ ] `gEq{|*|}` from `Data.Generics.GenEq`
- [ ] `gDefault{|*|}` from `Data.Generics.GenDefault`
- [ ] `GenFDomain` from `Data.Generics.GenFDomain`
- [ ] everything from `StdOverloaded`
- [ ] ...
_specific_ classes are for example:
- [ ] `JSONEncode, JSONDecode` from `Text.JSON`
- [ ] ...
## OS/Architecture specific functionality
When implementing functionality that is OS or Architecture specific it is preferred to implement it for all platforms.
This means that it is preferred to define a common interface to offer the same functionality on all platforms.
However, this is not always possible (e.g. PseudoTTY support is not available on windows) and therefore this is not mandatory.
The following guidelines should be adhered to when developing libraries for the
Clean Platform library collection.
== Type names ==
The names of types should be clear and informative, and should always start
with a capital. If the name of a type consists of multiple words, each new
word should start with a capital. The constructors of a type should also start
with a capital. Whenever the name is an abbreviation the abbreviation should be
written using only capitals (e.g. GUI,SQL,HTTP).
== Function names ==
Function names should *not* start with a capital, but when a function consists
of multiple words, each new word, except the first one should start with a
capital. By starting types and constructors with a capital and, functions
without one, the difference between a constructor and a function is immediately
clear for the reader of a program.
== Module names ==
For modules, the same guidelines apply as for naming types. Names should be
informative and preferably short. When a library module is not meant for direct
imports by end users, but should only used by experts in modules that for
example provide a more friendly interface, you should prefix the name of that
module with an underscore character.
== Argument order ==
While there are no hard demands on the order in which you specify the arguments
of functions, there are two rules which make your functions easier to use and
somewhat more clear:
* State representing arguments such as the common *World type argument,
should be at the end of the argument list.
* Arguments which are used as "options" in some way should be at the
beginning of the arguments. This makes it easy to pass in options by
currying.
== Comments ==
A concise description of the purpose of a function and the meaning of its input
and output parameters should be present in the .dcl file for all exported
functions. Comments are specified as follows:
/**
* This function is the identity.
*/
id :: a -> a
id x = x
The @param notation (similar to JavaDocs) can be used to clarify the arguments
separately.
== Layout ==
Whitespace and new lines can be used to format code nicely. When tabs are used
for alignment, they are considered to be fixed to four spaces.
== Exporting functions and types ===
Definition modules (.dcl) must be very specific about the modules they import
because everything imported in a definition module is exported as well,
increasing the chance of name collisions. To minimize the chance for
collisions, adhere to the following conventions:
* Explicitly import the types and classes you need for specifying the type
signatures by using the "from ... import ..." notation.
* Only ever import an entire module with the "import ..." notation if you
really truly want to re-export the entire module.
Implementation modules can be more liberal with what they import.
......@@ -8,16 +8,19 @@ from Data.Monoid import class Monoid, class Semigroup
:: Const a b = Const a
:: WrappedMonad m a = WrapMonad (m a)
unwrapMonad :: (WrappedMonad m a) -> m a
unwrapMonad :: !(WrappedMonad m a) -> m a
getConst :: (Const a b) -> a
getConst :: !(Const a b) -> a
instance Applicative ((->) r)
instance Applicative Maybe
instance Applicative []
class Applicative f | Functor f
where
pure :: a -> f a
(<*>) infixl 4 :: !(f (a -> b)) (f a) -> f b
instance Alternative Maybe
instance Alternative []
class Alternative f | Applicative f
where
empty :: f a
(<|>) infixl 3 :: !(f a) (f a) -> f a
instance Functor (Const m)
instance Functor (WrappedMonad m) | Monad m
......@@ -30,14 +33,6 @@ instance Alternative (WrappedMonad m) | MonadPlus m
instance Semigroup (Const a b) | Semigroup a
instance Monoid (Const a b) | Monoid a
class Applicative f | Functor f where
pure :: a -> f a
(<*>) infixl 4 :: (f (a -> b)) (f a) -> f b
class Alternative f | Applicative f where
empty :: f a
(<|>) infixl 3 :: (f a) (f a) -> f a
some :: (f a) -> f [a] | Alternative f
many :: (f a) -> f [a] | Alternative f
......@@ -52,9 +47,8 @@ many :: (f a) -> f [a] | Alternative f
* Be aware that the execution order has to be correct: the left hand side must
* be evaluated before the right hand side.
*/
class (*>) infixl 4 f :: (f a) (f b) -> f b | Applicative f
class (*>) infixl 4 f :: !(f a) (f b) -> f b | Applicative f
instance *> f
instance *> Maybe
/**
* Sequence actions and take the value of the left argument.
......@@ -63,9 +57,8 @@ instance *> Maybe
* Be aware that the execution order has to be correct: the left hand side must
* be evaluated before the right hand side.
*/
class (<*) infixl 4 f :: (f a) (f b) -> f a | Applicative f
class (<*) infixl 4 f :: !(f a) (f b) -> f a | Applicative f
instance <* f
instance <* Maybe
(<**>) infixl 4 :: (f a) (f (a -> b)) -> f b | Applicative f
......
......@@ -6,7 +6,7 @@ from Data.Monoid import class Monoid, class Semigroup
import qualified Data.Monoid as DM
from StdFunc import id, o, flip, const
getConst :: (Const a b) -> a
getConst :: !(Const a b) -> a
getConst (Const x) = x
instance Functor (Const m) where
......@@ -22,7 +22,7 @@ instance Applicative (Const m) | Monoid m where
pure _ = Const 'DM'.mempty
(<*>) (Const f) (Const v) = Const ('DM'.mappend f v)
unwrapMonad :: (WrappedMonad m a) -> m a
unwrapMonad :: !(WrappedMonad m a) -> m a
unwrapMonad (WrapMonad x) = x
instance Functor (WrappedMonad m) | Monad m where
......@@ -39,28 +39,6 @@ instance Alternative (WrappedMonad m) | MonadPlus m where
empty = WrapMonad mzero
(<|>) (WrapMonad u) (WrapMonad v) = WrapMonad (mplus u v)
instance Applicative ((->) r) where
pure x = const x
(<*>) f g = \x -> f x (g x)
instance Applicative Maybe where
pure x = Just x
(<*>) Nothing _ = Nothing
(<*>) (Just f) ma = fmap f ma
instance Applicative [] where
pure x = [x]
(<*>) xs x = liftA2 id xs x
instance Alternative Maybe where
empty = Nothing
(<|>) Nothing r = r
(<|>) l _ = l
instance Alternative [] where
empty = []
(<|>) fa fa` = fa ++ fa`
some :: (f a) -> f [a] | Alternative f
some v = some_v
where many_v = some_v <|> lift []
......@@ -73,19 +51,8 @@ many v = many_v
instance *> f where *> fa fb = id <$ fa <*> fb
instance *> Maybe
where
*> (Just _) m = m
*> _ _ = Nothing
instance <* f where <* fa fb = liftA2 const fa fb
instance <* Maybe
where
<* Nothing _ = Nothing
<* m (Just _) = m
<* _ _ = Nothing
(<**>) infixl 4 :: (f a) (f (a -> b)) -> f b | Applicative f
(<**>) fa fab = liftA2 (flip ($)) fa fab
......
......@@ -2,40 +2,39 @@ definition module Control.Monad
from Control.Applicative import class Applicative
from Data.Functor import class Functor
from Data.Maybe import :: Maybe
class Monad m | Applicative m where
bind :: (m a) (a -> m b) -> m b
class Monad m | Applicative m
where
bind :: !(m a) (a -> m b) -> m b
instance Monad ((->) r)
(>>=) infixl 1 :: (m a) (a -> m b) -> m b | Monad m
(>>=) ma a2mb :== bind ma a2mb
instance Monad []
(`b`) infixl 1 :: (m a) (a -> m b) -> m b | Monad m
(`b`) ma a2mb :== bind ma a2mb
instance Monad Maybe
(>>|) infixl 1 :: (m a) (m b) -> m b | Monad m
(>>|) ma mb :== ma >>= \_ -> mb
class MonadPlus m | Monad m where
mzero :: m a
mplus :: (m a) (m a) -> m a
(=<<) infixr 1 :: (a -> m b) (m a) -> m b | Monad m
(=<<) f x :== x >>= f
instance MonadPlus []
class MonadPlus m | Monad m
where
mzero :: m a
mplus :: !(m a) (m a) -> m a
instance MonadPlus Maybe
(>>=) infixl 1 :: (m a) (a -> m b) -> m b | Monad m
(`b`) infixl 1 :: (m a) (a -> m b) -> m b | Monad m
(>>|) infixl 1 :: (m a) (m b) -> m b | Monad m
(=<<) infixr 1 :: (a -> m b) (m a) -> m b | Monad m
sequence :: .[a b] -> a [b] | Monad a
sequence_ :: .[a b] -> a () | Monad a
mapM :: (.a -> b c) [.a] -> b [c] | Monad b
mapM_ :: (.a -> b c) [.a] -> b () | Monad b
sequence :: !.[a b] -> a [b] | Monad a
sequence_ :: !.[a b] -> a () | Monad a
mapM :: (.a -> b c) ![.a] -> b [c] | Monad b
mapM_ :: (.a -> b c) ![.a] -> b () | Monad b
forM :: u:([v:a] -> w:((v:a -> b c) -> b [c])) | Monad b, [w <= u,w <= v]
forM_ :: u:([v:a] -> w:((v:a -> b c) -> b ())) | Monad b, [w <= u,w <= v]
forever :: (a b) -> a c | Monad a
join :: (a (a b)) -> a b | Monad a
zipWithM :: (.a -> .(.b -> c d)) [.a] [.b] -> c [d] | Monad c
foldM :: (a -> .(b -> c a)) a [b] -> c a | Monad c
replicateM :: .Int (a b) -> a [b] | Monad a
zipWithM :: (.a -> .(.b -> c d)) ![.a] [.b] -> c [d] | Monad c
foldM :: (a -> .(b -> c a)) a ![b] -> c a | Monad c
replicateM :: !.Int (a b) -> a [b] | Monad a
(>=>) infixr 1 :: u:(.a -> b c) (c -> b d) -> v:(.a -> b d) | Monad b, [v <= u]
(<=<) infixr 1 :: u:((a -> b c) -> v:(w:(.d -> b a) -> x:(.d -> b c))) | Monad b, [v <= u,x <= w]
liftM :: (a -> b) (c a) -> c b | Monad c
......
......@@ -3,55 +3,22 @@ implementation module Control.Monad
from Control.Applicative import class Applicative (..), lift
from Data.Functor import class Functor (..)
from Data.List import map, zipWith, replicate
from Data.Maybe import :: Maybe, Nothing, Just
from StdList import foldr, ++
from StdList import foldr
from StdFunc import flip, id, o, const
from StdInt import class +, instance + Int
instance Monad ((->) r) where
bind ma a2mb = \r -> a2mb (ma r) r
instance Monad [] where
bind m k = foldr ((++) o k) [] m
instance Monad Maybe where
bind (Just x) k = k x
bind Nothing _ = Nothing
instance MonadPlus [] where
mzero = []
mplus xs ys = xs ++ ys
instance MonadPlus Maybe where
mzero = Nothing
mplus Nothing ys = ys
mplus xs _ = xs
(>>=) infixl 1 :: (m a) (a -> m b) -> m b | Monad m
(>>=) ma a2mb = bind ma a2mb
(`b`) infixl 1 :: (m a) (a -> m b) -> m b | Monad m
(`b`) ma a2mb = bind ma a2mb
(>>|) infixl 1 :: (m a) (m b) -> m b | Monad m
(>>|) ma mb = ma >>= \_ -> mb
(=<<) infixr 1 :: (a -> m b) (m a) -> m b | Monad m
(=<<) f x = x >>= f
sequence :: .[a b] -> a [b] | Monad a
sequence :: !.[a b] -> a [b] | Monad a
sequence ms = foldr k (lift []) ms
where
k m m` = m >>= \x -> m` >>= \xs -> lift [x:xs]
sequence_ :: .[a b] -> a () | Monad a
sequence_ :: !.[a b] -> a () | Monad a
sequence_ ms = foldr (>>|) (lift ()) ms
mapM :: (.a -> b c) [.a] -> b [c] | Monad b
mapM :: (.a -> b c) ![.a] -> b [c] | Monad b
mapM f as = sequence (map f as)
mapM_ :: (.a -> b c) [.a] -> b () | Monad b
mapM_ :: (.a -> b c) ![.a] -> b () | Monad b
mapM_ f as = sequence_ (map f as)
forM :: u:([v:a] -> w:((v:a -> b c) -> b [c])) | Monad b, [w <= u,w <= v]
......@@ -66,14 +33,14 @@ forever a = let a` = a >>| a` in a`
join :: (a (a b)) -> a b | Monad a
join x = x >>= id
zipWithM :: (.a -> .(.b -> c d)) [.a] [.b] -> c [d] | Monad c
zipWithM :: (.a -> .(.b -> c d)) ![.a] [.b] -> c [d] | Monad c
zipWithM f xs ys = sequence (zipWith f xs ys)
foldM :: (a -> .(b -> c a)) a [b] -> c a | Monad c
foldM :: (a -> .(b -> c a)) a ![b] -> c a | Monad c
foldM _ a [] = lift a
foldM f a [x:xs] = f a x >>= \fax -> foldM f fax xs
replicateM :: .Int (a b) -> a [b] | Monad a
replicateM :: !.Int (a b) -> a [b] | Monad a
replicateM n x = sequence (replicate n x)
(>=>) infixr 1 :: u:(.a -> b c) (c -> b d) -> v:(.a -> b d) | Monad b, [v <= u]
......
......@@ -3,7 +3,7 @@ implementation module Control.Monad.Fix
from StdFunc import o
from StdMisc import abort
import Control.Applicative
from Control.Monad import class Monad, instance Monad []
from Control.Monad import class Monad
from Data.Func import fix
import Data.List
import Data.Maybe
......
......@@ -63,7 +63,7 @@ evalRWST m r s
execRWST :: (RWST r w s m a) r s -> m (s, w) | Monad m
execRWST m r s
= runRWST m r s
>>= \(_, s`, w) -> pure (s, w)
>>= \(_, s`, w) -> pure (s`, w)
mapRWST :: ((m (a, s, w)) -> n (b, s, w`)) (RWST r w s m a) -> RWST r w` s n b
mapRWST f m = RWST (\r s -> f (runRWST m r s))
......
......@@ -20,7 +20,7 @@ from System.File import :: FileError
* @param The message for which to compute the digest
* @return The ascii hex representation of the message digest
*/
sha1 :: String -> String
sha1 :: !String -> String
/**
* Compute the SHA1 digest of a string
......@@ -28,7 +28,7 @@ sha1 :: String -> String
* @param The message for which to compute the digest
* @return The raw 160 bit digest
*/
sha1StringDigest :: String -> SHA1Digest
sha1StringDigest :: !String -> SHA1Digest
/**
* Compute the SHA1 digest of the contents of a file
......@@ -38,7 +38,7 @@ sha1StringDigest :: String -> SHA1Digest
* @return The raw 160 bit digest
* @return The environment
*/
sha1FileDigest :: FilePath *env -> (!MaybeError FileError SHA1Digest,!*env) | FileSystem env
sha1FileDigest :: !FilePath !*env -> (!MaybeError FileError SHA1Digest, !*env) | FileSystem env
/**
* Print a SHA1 digest as ascii hexadecimal form
......
......@@ -12,10 +12,10 @@ import Data.Tuple, Text, System.FilePath, System.File, Data.Error, Data.Functor
*/
:: SHA1Digest = SHA1Digest {#Char} // 160 bit (20byte) message digest
sha1 :: String -> String
sha1 :: !String -> String
sha1 msg = toString (sha1StringDigest msg)
sh