From 970637279c95bf4a4c371aaac921cc42d5c6137d Mon Sep 17 00:00:00 2001 From: Gary Burgess Date: Sat, 19 Dec 2015 01:09:35 +0000 Subject: [PATCH] Updates for PureScript 0.8 --- .jscsrc | 5 + .jshintrc | 3 +- .travis.yml | 11 +- README.md | 7 +- bower.json | 4 - docs/Prelude.md | 986 ---------------------------------- package.json | 11 +- src/Control/Applicative.purs | 64 +++ src/Control/Apply.js | 16 + src/Control/Apply.purs | 78 +++ src/Control/Bind.js | 13 + src/Control/Bind.purs | 103 ++++ src/Control/Category.purs | 20 + src/Control/Monad.purs | 63 +++ src/Control/Semigroupoid.purs | 24 + src/Data/Boolean.purs | 10 + src/Data/BooleanAlgebra.js | 19 + src/Data/BooleanAlgebra.purs | 63 +++ src/Data/Bounded.js | 9 + src/Data/Bounded.purs | 44 ++ src/Data/BoundedOrd.purs | 24 + src/Data/DivisionRing.purs | 25 + src/Data/Eq.js | 27 + src/Data/Eq.purs | 51 ++ src/Data/Function.purs | 89 +++ src/Data/Functor.js | 14 + src/Data/Functor.purs | 72 +++ src/Data/ModuloSemiring.js | 22 + src/Data/ModuloSemiring.purs | 37 ++ src/Data/Num.purs | 24 + src/Data/Ord.js | 41 ++ src/Data/Ord.purs | 150 ++++++ src/Data/Ord/Unsafe.js | 15 + src/Data/Ord/Unsafe.purs | 15 + src/Data/Ordering.purs | 41 ++ src/Data/Ring.js | 16 + src/Data/Ring.purs | 35 ++ src/Data/Semigroup.js | 15 + src/Data/Semigroup.purs | 31 ++ src/Data/Semiring.js | 29 + src/Data/Semiring.purs | 51 ++ src/Data/Show.js | 63 +++ src/Data/Show.purs | 35 ++ src/Data/Unit.js | 5 + src/Data/Unit.purs | 17 + src/Data/Void.purs | 13 + src/Prelude.js | 261 --------- src/Prelude.purs | 918 ++----------------------------- 48 files changed, 1559 insertions(+), 2130 deletions(-) delete mode 100644 docs/Prelude.md create mode 100644 src/Control/Applicative.purs create mode 100644 src/Control/Apply.js create mode 100644 src/Control/Apply.purs create mode 100644 src/Control/Bind.js create mode 100644 src/Control/Bind.purs create mode 100644 src/Control/Category.purs create mode 100644 src/Control/Monad.purs create mode 100644 src/Control/Semigroupoid.purs create mode 100644 src/Data/Boolean.purs create mode 100644 src/Data/BooleanAlgebra.js create mode 100644 src/Data/BooleanAlgebra.purs create mode 100644 src/Data/Bounded.js create mode 100644 src/Data/Bounded.purs create mode 100644 src/Data/BoundedOrd.purs create mode 100644 src/Data/DivisionRing.purs create mode 100644 src/Data/Eq.js create mode 100644 src/Data/Eq.purs create mode 100644 src/Data/Function.purs create mode 100644 src/Data/Functor.js create mode 100644 src/Data/Functor.purs create mode 100644 src/Data/ModuloSemiring.js create mode 100644 src/Data/ModuloSemiring.purs create mode 100644 src/Data/Num.purs create mode 100644 src/Data/Ord.js create mode 100644 src/Data/Ord.purs create mode 100644 src/Data/Ord/Unsafe.js create mode 100644 src/Data/Ord/Unsafe.purs create mode 100644 src/Data/Ordering.purs create mode 100644 src/Data/Ring.js create mode 100644 src/Data/Ring.purs create mode 100644 src/Data/Semigroup.js create mode 100644 src/Data/Semigroup.purs create mode 100644 src/Data/Semiring.js create mode 100644 src/Data/Semiring.purs create mode 100644 src/Data/Show.js create mode 100644 src/Data/Show.purs create mode 100644 src/Data/Unit.js create mode 100644 src/Data/Unit.purs create mode 100644 src/Data/Void.purs delete mode 100644 src/Prelude.js diff --git a/.jscsrc b/.jscsrc index 342da669..2561ce9e 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,5 +1,10 @@ { "preset": "grunt", + "disallowSpacesInFunctionExpression": null, + "requireSpacesInFunctionExpression": { + "beforeOpeningRoundBrace": true, + "beforeOpeningCurlyBrace": true + }, "disallowSpacesInAnonymousFunctionExpression": null, "requireSpacesInAnonymousFunctionExpression": { "beforeOpeningRoundBrace": true, diff --git a/.jshintrc b/.jshintrc index 2240be2a..620d8d7f 100644 --- a/.jshintrc +++ b/.jshintrc @@ -15,5 +15,6 @@ "singleGroups": true, "undef": true, "unused": true, - "eqnull": true + "eqnull": true, + "predef": ["exports"] } diff --git a/.travis.yml b/.travis.yml index 791313a3..851998bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js sudo: false node_js: - - 0.10 + - 5 env: - PATH=$HOME/purescript:$PATH install: @@ -9,6 +9,15 @@ install: - wget -O $HOME/purescript.tar.gz https://github.com/purescript/purescript/releases/download/$TAG/linux64.tar.gz - tar -xvf $HOME/purescript.tar.gz -C $HOME/ - chmod a+x $HOME/purescript + - npm install -g bower - npm install script: - npm run build +after_success: +- >- + test $TRAVIS_TAG && + psc-publish > .pursuit.json && + curl -X POST http://pursuit.purescript.org/packages \ + -d @.pursuit.json \ + -H 'Accept: application/json' \ + -H "Authorization: token ${GITHUB_TOKEN}" diff --git a/README.md b/README.md index 5087b3a2..5d22ec72 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Latest release](http://img.shields.io/bower/v/purescript-prelude.svg)](https://github.com/purescript/purescript-prelude/releases) [![Build Status](https://travis-ci.org/purescript/purescript-prelude.svg?branch=master)](https://travis-ci.org/purescript/purescript-prelude) -The PureScript prelude. For use with compiler version >= 0.7. +The PureScript prelude. ## Installation @@ -11,6 +11,7 @@ The PureScript prelude. For use with compiler version >= 0.7. bower install purescript-prelude ``` -## Module documentation +## Documentation + +Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-prelude). -- [Prelude](docs/Prelude.md) diff --git a/bower.json b/bower.json index 4182b355..996ec6e2 100644 --- a/bower.json +++ b/bower.json @@ -2,9 +2,6 @@ "name": "purescript-prelude", "homepage": "https://github.com/purescript/purescript-prelude", "description": "The PureScript Prelude", - "keywords": [ - "purescript" - ], "license": "MIT", "repository": { "type": "git", @@ -17,7 +14,6 @@ "output", "test", "bower.json", - "gulpfile.js", "package.json" ] } diff --git a/docs/Prelude.md b/docs/Prelude.md deleted file mode 100644 index df56019c..00000000 --- a/docs/Prelude.md +++ /dev/null @@ -1,986 +0,0 @@ -## Module Prelude - -#### `Unit` - -``` purescript -newtype Unit -``` - -The `Unit` type has a single inhabitant, called `unit`. It represents -values with no computational content. - -`Unit` is often used, wrapped in a monadic type constructor, as the -return type of a computation where only -the _effects_ are important. - -##### Instances -``` purescript -instance semigroupUnit :: Semigroup Unit -instance semiringUnit :: Semiring Unit -instance ringUnit :: Ring Unit -instance moduloSemiringUnit :: ModuloSemiring Unit -instance divisionRingUnit :: DivisionRing Unit -instance numUnit :: Num Unit -instance eqUnit :: Eq Unit -instance ordUnit :: Ord Unit -instance boundedUnit :: Bounded Unit -instance boundedOrdUnit :: BoundedOrd Unit -instance booleanAlgebraUnit :: BooleanAlgebra Unit -instance showUnit :: Show Unit -``` - -#### `unit` - -``` purescript -unit :: Unit -``` - -`unit` is the sole inhabitant of the `Unit` type. - -#### `($)` - -``` purescript -($) :: forall a b. (a -> b) -> a -> b -``` - -_right-associative / precedence 0_ - -Applies a function to its argument. - -```purescript -length $ groupBy productCategory $ filter isInStock $ products -``` - -is equivalent to: - -```purescript -length (groupBy productCategory (filter isInStock products)) -``` - -`($)` is different from [`(#)`](#-2) because it is right-infix instead of -left: `a $ b $ c $ d x = a $ (b $ (c $ (d $ x))) = a (b (c (d x)))` - -#### `(#)` - -``` purescript -(#) :: forall a b. a -> (a -> b) -> b -``` - -_left-associative / precedence 1_ - -Applies an argument to a function. - -```purescript -products # filter isInStock # groupBy productCategory # length -``` - -is equivalent to: - -```purescript -length (groupBy productCategory (filter isInStock products)) -``` - -`(#)` is different from [`($)`](#-1) because it is left-infix instead of -right: `x # a # b # c # d = (((x # a) # b) # c) # d = d (c (b (a x)))` - -#### `flip` - -``` purescript -flip :: forall a b c. (a -> b -> c) -> b -> a -> c -``` - -Flips the order of the arguments to a function of two arguments. - -```purescript -flip const 1 2 = const 2 1 = 2 -``` - -#### `const` - -``` purescript -const :: forall a b. a -> b -> a -``` - -Returns its first argument and ignores its second. - -```purescript -const 1 "hello" = 1 -``` - -#### `asTypeOf` - -``` purescript -asTypeOf :: forall a. a -> a -> a -``` - -This function returns its first argument, and can be used to assert type -equalities. This can be useful when types are otherwise ambiguous. - -```purescript -main = print $ [] `asTypeOf` [0] -``` - -If instead, we had written `main = print []`, the type of the argument -`[]` would have been ambiguous, resulting in a compile-time error. - -#### `otherwise` - -``` purescript -otherwise :: Boolean -``` - -An alias for `true`, which can be useful in guard clauses: - -```purescript -max x y | x >= y = x - | otherwise = y -``` - -#### `Semigroupoid` - -``` purescript -class Semigroupoid a where - compose :: forall b c d. a c d -> a b c -> a b d -``` - -A `Semigroupoid` is similar to a [`Category`](#category) but does not -require an identity element `id`, just composable morphisms. - -`Semigroupoid`s must satisfy the following law: - -- Associativity: `p <<< (q <<< r) = (p <<< q) <<< r` - -One example of a `Semigroupoid` is the function type constructor `(->)`, -with `(<<<)` defined as function composition. - -##### Instances -``` purescript -instance semigroupoidFn :: Semigroupoid Function -``` - -#### `(<<<)` - -``` purescript -(<<<) :: forall a b c d. (Semigroupoid a) => a c d -> a b c -> a b d -``` - -_right-associative / precedence 9_ - -`(<<<)` is an alias for `compose`. - -#### `(>>>)` - -``` purescript -(>>>) :: forall a b c d. (Semigroupoid a) => a b c -> a c d -> a b d -``` - -_right-associative / precedence 9_ - -Forwards composition, or `(<<<)` with its arguments reversed. - -#### `Category` - -``` purescript -class (Semigroupoid a) <= Category a where - id :: forall t. a t t -``` - -`Category`s consist of objects and composable morphisms between them, and -as such are [`Semigroupoids`](#semigroupoid), but unlike `semigroupoids` -must have an identity element. - -Instances must satisfy the following law in addition to the -`Semigroupoid` law: - -- Identity: `id <<< p = p <<< id = p` - -##### Instances -``` purescript -instance categoryFn :: Category Function -``` - -#### `Functor` - -``` purescript -class Functor f where - map :: forall a b. (a -> b) -> f a -> f b -``` - -A `Functor` is a type constructor which supports a mapping operation -`(<$>)`. - -`(<$>)` can be used to turn functions `a -> b` into functions -`f a -> f b` whose argument and return types use the type constructor `f` -to represent some computational context. - -Instances must satisfy the following laws: - -- Identity: `(<$>) id = id` -- Composition: `(<$>) (f <<< g) = (f <$>) <<< (g <$>)` - -##### Instances -``` purescript -instance functorFn :: Functor (Function r) -instance functorArray :: Functor Array -``` - -#### `(<$>)` - -``` purescript -(<$>) :: forall f a b. (Functor f) => (a -> b) -> f a -> f b -``` - -_left-associative / precedence 4_ - -`(<$>)` is an alias for `map` - -#### `(<#>)` - -``` purescript -(<#>) :: forall f a b. (Functor f) => f a -> (a -> b) -> f b -``` - -_left-associative / precedence 1_ - -`(<#>)` is `(<$>)` with its arguments reversed. For example: - -```purescript -[1, 2, 3] <#> \n -> n * n -``` - -#### `void` - -``` purescript -void :: forall f a. (Functor f) => f a -> f Unit -``` - -The `void` function is used to ignore the type wrapped by a -[`Functor`](#functor), replacing it with `Unit` and keeping only the type -information provided by the type constructor itself. - -`void` is often useful when using `do` notation to change the return type -of a monadic computation: - -```purescript -main = forE 1 10 \n -> void do - print n - print (n * n) -``` - -#### `Apply` - -``` purescript -class (Functor f) <= Apply f where - apply :: forall a b. f (a -> b) -> f a -> f b -``` - -The `Apply` class provides the `(<*>)` which is used to apply a function -to an argument under a type constructor. - -`Apply` can be used to lift functions of two or more arguments to work on -values wrapped with the type constructor `f`. It might also be understood -in terms of the `lift2` function: - -```purescript -lift2 :: forall f a b c. (Apply f) => (a -> b -> c) -> f a -> f b -> f c -lift2 f a b = f <$> a <*> b -``` - -`(<*>)` is recovered from `lift2` as `lift2 ($)`. That is, `(<*>)` lifts -the function application operator `($)` to arguments wrapped with the -type constructor `f`. - -Instances must satisfy the following law in addition to the `Functor` -laws: - -- Associative composition: `(<<<) <$> f <*> g <*> h = f <*> (g <*> h)` - -Formally, `Apply` represents a strong lax semi-monoidal endofunctor. - -##### Instances -``` purescript -instance applyFn :: Apply (Function r) -instance applyArray :: Apply Array -``` - -#### `(<*>)` - -``` purescript -(<*>) :: forall f a b. (Apply f) => f (a -> b) -> f a -> f b -``` - -_left-associative / precedence 4_ - -`(<*>)` is an alias for `apply`. - -#### `Applicative` - -``` purescript -class (Apply f) <= Applicative f where - pure :: forall a. a -> f a -``` - -The `Applicative` type class extends the [`Apply`](#apply) type class -with a `pure` function, which can be used to create values of type `f a` -from values of type `a`. - -Where [`Apply`](#apply) provides the ability to lift functions of two or -more arguments to functions whose arguments are wrapped using `f`, and -[`Functor`](#functor) provides the ability to lift functions of one -argument, `pure` can be seen as the function which lifts functions of -_zero_ arguments. That is, `Applicative` functors support a lifting -operation for any number of function arguments. - -Instances must satisfy the following laws in addition to the `Apply` -laws: - -- Identity: `(pure id) <*> v = v` -- Composition: `(pure <<<) <*> f <*> g <*> h = f <*> (g <*> h)` -- Homomorphism: `(pure f) <*> (pure x) = pure (f x)` -- Interchange: `u <*> (pure y) = (pure ($ y)) <*> u` - -##### Instances -``` purescript -instance applicativeFn :: Applicative (Function r) -instance applicativeArray :: Applicative Array -``` - -#### `return` - -``` purescript -return :: forall m a. (Applicative m) => a -> m a -``` - -`return` is an alias for `pure`. - -#### `liftA1` - -``` purescript -liftA1 :: forall f a b. (Applicative f) => (a -> b) -> f a -> f b -``` - -`liftA1` provides a default implementation of `(<$>)` for any -[`Applicative`](#applicative) functor, without using `(<$>)` as provided -by the [`Functor`](#functor)-[`Applicative`](#applicative) superclass -relationship. - -`liftA1` can therefore be used to write [`Functor`](#functor) instances -as follows: - -```purescript -instance functorF :: Functor F where - map = liftA1 -``` - -#### `Bind` - -``` purescript -class (Apply m) <= Bind m where - bind :: forall a b. m a -> (a -> m b) -> m b -``` - -The `Bind` type class extends the [`Apply`](#apply) type class with a -"bind" operation `(>>=)` which composes computations in sequence, using -the return value of one computation to determine the next computation. - -The `>>=` operator can also be expressed using `do` notation, as follows: - -```purescript -x >>= f = do y <- x - f y -``` - -where the function argument of `f` is given the name `y`. - -Instances must satisfy the following law in addition to the `Apply` -laws: - -- Associativity: `(x >>= f) >>= g = x >>= (\k => f k >>= g)` - -Associativity tells us that we can regroup operations which use `do` -notation so that we can unambiguously write, for example: - -```purescript -do x <- m1 - y <- m2 x - m3 x y -``` - -##### Instances -``` purescript -instance bindFn :: Bind (Function r) -instance bindArray :: Bind Array -``` - -#### `(>>=)` - -``` purescript -(>>=) :: forall m a b. (Bind m) => m a -> (a -> m b) -> m b -``` - -_left-associative / precedence 1_ - -`(>>=)` is an alias for `bind`. - -#### `Monad` - -``` purescript -class (Applicative m, Bind m) <= Monad m -``` - -The `Monad` type class combines the operations of the `Bind` and -`Applicative` type classes. Therefore, `Monad` instances represent type -constructors which support sequential composition, and also lifting of -functions of arbitrary arity. - -Instances must satisfy the following laws in addition to the -`Applicative` and `Bind` laws: - -- Left Identity: `pure x >>= f = f x` -- Right Identity: `x >>= pure = x` - -##### Instances -``` purescript -instance monadFn :: Monad (Function r) -instance monadArray :: Monad Array -``` - -#### `liftM1` - -``` purescript -liftM1 :: forall m a b. (Monad m) => (a -> b) -> m a -> m b -``` - -`liftM1` provides a default implementation of `(<$>)` for any -[`Monad`](#monad), without using `(<$>)` as provided by the -[`Functor`](#functor)-[`Monad`](#monad) superclass relationship. - -`liftM1` can therefore be used to write [`Functor`](#functor) instances -as follows: - -```purescript -instance functorF :: Functor F where - map = liftM1 -``` - -#### `ap` - -``` purescript -ap :: forall m a b. (Monad m) => m (a -> b) -> m a -> m b -``` - -`ap` provides a default implementation of `(<*>)` for any -[`Monad`](#monad), without using `(<*>)` as provided by the -[`Apply`](#apply)-[`Monad`](#monad) superclass relationship. - -`ap` can therefore be used to write [`Apply`](#apply) instances as -follows: - -```purescript -instance applyF :: Apply F where - apply = ap -``` - -#### `Semigroup` - -``` purescript -class Semigroup a where - append :: a -> a -> a -``` - -The `Semigroup` type class identifies an associative operation on a type. - -Instances are required to satisfy the following law: - -- Associativity: `(x <> y) <> z = x <> (y <> z)` - -One example of a `Semigroup` is `String`, with `(<>)` defined as string -concatenation. - -##### Instances -``` purescript -instance semigroupString :: Semigroup String -instance semigroupUnit :: Semigroup Unit -instance semigroupFn :: (Semigroup s') => Semigroup (s -> s') -instance semigroupOrdering :: Semigroup Ordering -instance semigroupArray :: Semigroup (Array a) -``` - -#### `(<>)` - -``` purescript -(<>) :: forall s. (Semigroup s) => s -> s -> s -``` - -_right-associative / precedence 5_ - -`(<>)` is an alias for `append`. - -#### `(++)` - -``` purescript -(++) :: forall s. (Semigroup s) => s -> s -> s -``` - -_right-associative / precedence 5_ - -`(++)` is an alternative alias for `append`. - -#### `Semiring` - -``` purescript -class Semiring a where - add :: a -> a -> a - zero :: a - mul :: a -> a -> a - one :: a -``` - -The `Semiring` class is for types that support an addition and -multiplication operation. - -Instances must satisfy the following laws: - -- Commutative monoid under addition: - - Associativity: `(a + b) + c = a + (b + c)` - - Identity: `zero + a = a + zero = a` - - Commutative: `a + b = b + a` -- Monoid under multiplication: - - Associativity: `(a * b) * c = a * (b * c)` - - Identity: `one * a = a * one = a` -- Multiplication distributes over addition: - - Left distributivity: `a * (b + c) = (a * b) + (a * c)` - - Right distributivity: `(a + b) * c = (a * c) + (b * c)` -- Annihiliation: `zero * a = a * zero = zero` - -##### Instances -``` purescript -instance semiringInt :: Semiring Int -instance semiringNumber :: Semiring Number -instance semiringUnit :: Semiring Unit -``` - -#### `(+)` - -``` purescript -(+) :: forall a. (Semiring a) => a -> a -> a -``` - -_left-associative / precedence 6_ - -`(+)` is an alias for `add`. - -#### `(*)` - -``` purescript -(*) :: forall a. (Semiring a) => a -> a -> a -``` - -_left-associative / precedence 7_ - -`(*)` is an alias for `mul`. - -#### `Ring` - -``` purescript -class (Semiring a) <= Ring a where - sub :: a -> a -> a -``` - -The `Ring` class is for types that support addition, multiplication, -and subtraction operations. - -Instances must satisfy the following law in addition to the `Semiring` -laws: - -- Additive inverse: `a - a = (zero - a) + a = zero` - -##### Instances -``` purescript -instance ringInt :: Ring Int -instance ringNumber :: Ring Number -instance ringUnit :: Ring Unit -``` - -#### `(-)` - -``` purescript -(-) :: forall a. (Ring a) => a -> a -> a -``` - -_left-associative / precedence 6_ - -`(-)` is an alias for `sub`. - -#### `negate` - -``` purescript -negate :: forall a. (Ring a) => a -> a -``` - -`negate x` can be used as a shorthand for `zero - x`. - -#### `ModuloSemiring` - -``` purescript -class (Semiring a) <= ModuloSemiring a where - div :: a -> a -> a - mod :: a -> a -> a -``` - -The `ModuloSemiring` class is for types that support addition, -multiplication, division, and modulo (division remainder) operations. - -Instances must satisfy the following law in addition to the `Semiring` -laws: - -- Remainder: ``a / b * b + (a `mod` b) = a`` - -##### Instances -``` purescript -instance moduloSemiringInt :: ModuloSemiring Int -instance moduloSemiringNumber :: ModuloSemiring Number -instance moduloSemiringUnit :: ModuloSemiring Unit -``` - -#### `(/)` - -``` purescript -(/) :: forall a. (ModuloSemiring a) => a -> a -> a -``` - -_left-associative / precedence 7_ - -`(/)` is an alias for `div`. - -#### `DivisionRing` - -``` purescript -class (Ring a, ModuloSemiring a) <= DivisionRing a -``` - -A `Ring` where every nonzero element has a multiplicative inverse. - -Instances must satisfy the following law in addition to the `Ring` and -`ModuloSemiring` laws: - -- Multiplicative inverse: `(one / x) * x = one` - -As a consequence of this ```a `mod` b = zero``` as no divide operation -will have a remainder. - -##### Instances -``` purescript -instance divisionRingNumber :: DivisionRing Number -instance divisionRingUnit :: DivisionRing Unit -``` - -#### `Num` - -``` purescript -class (DivisionRing a) <= Num a -``` - -The `Num` class is for types that are commutative fields. - -Instances must satisfy the following law in addition to the -`DivisionRing` laws: - -- Commutative multiplication: `a * b = b * a` - -##### Instances -``` purescript -instance numNumber :: Num Number -instance numUnit :: Num Unit -``` - -#### `Eq` - -``` purescript -class Eq a where - eq :: a -> a -> Boolean -``` - -The `Eq` type class represents types which support decidable equality. - -`Eq` instances should satisfy the following laws: - -- Reflexivity: `x == x = true` -- Symmetry: `x == y = y == x` -- Transitivity: if `x == y` and `y == z` then `x == z` - -##### Instances -``` purescript -instance eqBoolean :: Eq Boolean -instance eqInt :: Eq Int -instance eqNumber :: Eq Number -instance eqChar :: Eq Char -instance eqString :: Eq String -instance eqUnit :: Eq Unit -instance eqArray :: (Eq a) => Eq (Array a) -instance eqOrdering :: Eq Ordering -``` - -#### `(==)` - -``` purescript -(==) :: forall a. (Eq a) => a -> a -> Boolean -``` - -_non-associative / precedence 4_ - -`(==)` is an alias for `eq`. Tests whether one value is equal to another. - -#### `(/=)` - -``` purescript -(/=) :: forall a. (Eq a) => a -> a -> Boolean -``` - -_non-associative / precedence 4_ - -`(/=)` tests whether one value is _not equal_ to another. Shorthand for -`not (x == y)`. - -#### `Ordering` - -``` purescript -data Ordering - = LT - | GT - | EQ -``` - -The `Ordering` data type represents the three possible outcomes of -comparing two values: - -`LT` - The first value is _less than_ the second. -`GT` - The first value is _greater than_ the second. -`EQ` - The first value is _equal to_ the second. - -##### Instances -``` purescript -instance semigroupOrdering :: Semigroup Ordering -instance eqOrdering :: Eq Ordering -instance ordOrdering :: Ord Ordering -instance boundedOrdering :: Bounded Ordering -instance boundedOrdOrdering :: BoundedOrd Ordering -instance showOrdering :: Show Ordering -``` - -#### `Ord` - -``` purescript -class (Eq a) <= Ord a where - compare :: a -> a -> Ordering -``` - -The `Ord` type class represents types which support comparisons with a -_total order_. - -`Ord` instances should satisfy the laws of total orderings: - -- Reflexivity: `a <= a` -- Antisymmetry: if `a <= b` and `b <= a` then `a = b` -- Transitivity: if `a <= b` and `b <= c` then `a <= c` - -##### Instances -``` purescript -instance ordBoolean :: Ord Boolean -instance ordInt :: Ord Int -instance ordNumber :: Ord Number -instance ordString :: Ord String -instance ordChar :: Ord Char -instance ordUnit :: Ord Unit -instance ordArray :: (Ord a) => Ord (Array a) -instance ordOrdering :: Ord Ordering -``` - -#### `(<)` - -``` purescript -(<) :: forall a. (Ord a) => a -> a -> Boolean -``` - -_left-associative / precedence 4_ - -Test whether one value is _strictly less than_ another. - -#### `(>)` - -``` purescript -(>) :: forall a. (Ord a) => a -> a -> Boolean -``` - -_left-associative / precedence 4_ - -Test whether one value is _strictly greater than_ another. - -#### `(<=)` - -``` purescript -(<=) :: forall a. (Ord a) => a -> a -> Boolean -``` - -_left-associative / precedence 4_ - -Test whether one value is _non-strictly less than_ another. - -#### `(>=)` - -``` purescript -(>=) :: forall a. (Ord a) => a -> a -> Boolean -``` - -_left-associative / precedence 4_ - -Test whether one value is _non-strictly greater than_ another. - -#### `unsafeCompare` - -``` purescript -unsafeCompare :: forall a. a -> a -> Ordering -``` - -#### `Bounded` - -``` purescript -class Bounded a where - top :: a - bottom :: a -``` - -The `Bounded` type class represents types that are finite. - -Although there are no "internal" laws for `Bounded`, every value of `a` -should be considered less than or equal to `top` by some means, and greater -than or equal to `bottom`. - -The lack of explicit `Ord` constraint allows flexibility in the use of -`Bounded` so it can apply to total and partially ordered sets, boolean -algebras, etc. - -##### Instances -``` purescript -instance boundedBoolean :: Bounded Boolean -instance boundedUnit :: Bounded Unit -instance boundedOrdering :: Bounded Ordering -instance boundedInt :: Bounded Int -instance boundedChar :: Bounded Char -instance boundedFn :: (Bounded b) => Bounded (a -> b) -``` - -#### `BoundedOrd` - -``` purescript -class (Bounded a, Ord a) <= BoundedOrd a -``` - -The `BoundedOrd` type class represents totally ordered finite data types. - -Instances should satisfy the following law in addition to the `Ord` laws: - -- Ordering: `bottom <= a <= top` - -##### Instances -``` purescript -instance boundedOrdBoolean :: BoundedOrd Boolean -instance boundedOrdUnit :: BoundedOrd Unit -instance boundedOrdOrdering :: BoundedOrd Ordering -instance boundedOrdInt :: BoundedOrd Int -instance boundedOrdChar :: BoundedOrd Char -``` - -#### `BooleanAlgebra` - -``` purescript -class (Bounded a) <= BooleanAlgebra a where - conj :: a -> a -> a - disj :: a -> a -> a - not :: a -> a -``` - -The `BooleanAlgebra` type class represents types that behave like boolean -values. - -Instances should satisfy the following laws in addition to the `Bounded` -laws: - -- Associativity: - - `a || (b || c) = (a || b) || c` - - `a && (b && c) = (a && b) && c` -- Commutativity: - - `a || b = b || a` - - `a && b = b && a` -- Distributivity: - - `a && (b || c) = (a && b) || (a && c)` - - `a || (b && c) = (a || b) && (a || c)` -- Identity: - - `a || bottom = a` - - `a && top = a` -- Idempotent: - - `a || a = a` - - `a && a = a` -- Absorption: - - `a || (a && b) = a` - - `a && (a || b) = a` -- Annhiliation: - - `a || top = top` -- Complementation: - - `a && not a = bottom` - - `a || not a = top` - -##### Instances -``` purescript -instance booleanAlgebraBoolean :: BooleanAlgebra Boolean -instance booleanAlgebraUnit :: BooleanAlgebra Unit -instance booleanAlgebraFn :: (BooleanAlgebra b) => BooleanAlgebra (a -> b) -``` - -#### `(&&)` - -``` purescript -(&&) :: forall a. (BooleanAlgebra a) => a -> a -> a -``` - -_right-associative / precedence 3_ - -`(&&)` is an alias for `conj`. - -#### `(||)` - -``` purescript -(||) :: forall a. (BooleanAlgebra a) => a -> a -> a -``` - -_right-associative / precedence 2_ - -`(||)` is an alias for `disj`. - -#### `Show` - -``` purescript -class Show a where - show :: a -> String -``` - -The `Show` type class represents those types which can be converted into -a human-readable `String` representation. - -While not required, it is recommended that for any expression `x`, the -string `show x` be executable PureScript code which evaluates to the same -value as the expression `x`. - -##### Instances -``` purescript -instance showBoolean :: Show Boolean -instance showInt :: Show Int -instance showNumber :: Show Number -instance showChar :: Show Char -instance showString :: Show String -instance showUnit :: Show Unit -instance showArray :: (Show a) => Show (Array a) -instance showOrdering :: Show Ordering -``` - - diff --git a/package.json b/package.json index e129c496..b326108a 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,13 @@ "private": true, "scripts": { "postinstall": "pulp dep install", - "build": "jshint src && jscs src && pulp build && rimraf docs && pulp docs" + "clean": "rimraf output && rimraf .pulp-cache", + "build": "jshint src && jscs src && pulp build" }, "devDependencies": { - "jscs": "^1.13.1", - "jshint": "^2.8.0", - "pulp": "^4.0.2", - "rimraf": "^2.4.1" + "jscs": "^2.8.0", + "jshint": "^2.9.1", + "pulp": "^8.0.0", + "rimraf": "^2.5.0" } } diff --git a/src/Control/Applicative.purs b/src/Control/Applicative.purs new file mode 100644 index 00000000..34cb6d8b --- /dev/null +++ b/src/Control/Applicative.purs @@ -0,0 +1,64 @@ +module Control.Applicative + ( class Applicative, pure + , liftA1 + , unless, when + , module Control.Apply + , module Data.Functor + ) where + +import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) + +import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) +import Data.Unit (Unit, unit) + +-- | The `Applicative` type class extends the [`Apply`](#apply) type class +-- | with a `pure` function, which can be used to create values of type `f a` +-- | from values of type `a`. +-- | +-- | Where [`Apply`](#apply) provides the ability to lift functions of two or +-- | more arguments to functions whose arguments are wrapped using `f`, and +-- | [`Functor`](#functor) provides the ability to lift functions of one +-- | argument, `pure` can be seen as the function which lifts functions of +-- | _zero_ arguments. That is, `Applicative` functors support a lifting +-- | operation for any number of function arguments. +-- | +-- | Instances must satisfy the following laws in addition to the `Apply` +-- | laws: +-- | +-- | - Identity: `(pure id) <*> v = v` +-- | - Composition: `(pure <<<) <*> f <*> g <*> h = f <*> (g <*> h)` +-- | - Homomorphism: `(pure f) <*> (pure x) = pure (f x)` +-- | - Interchange: `u <*> (pure y) = (pure ($ y)) <*> u` +class Apply f <= Applicative f where + pure :: forall a. a -> f a + +instance applicativeFn :: Applicative ((->) r) where + pure x _ = x + +instance applicativeArray :: Applicative Array where + pure x = [x] + +-- | `liftA1` provides a default implementation of `(<$>)` for any +-- | [`Applicative`](#applicative) functor, without using `(<$>)` as provided +-- | by the [`Functor`](#functor)-[`Applicative`](#applicative) superclass +-- | relationship. +-- | +-- | `liftA1` can therefore be used to write [`Functor`](#functor) instances +-- | as follows: +-- | +-- | ```purescript +-- | instance functorF :: Functor F where +-- | map = liftA1 +-- | ``` +liftA1 :: forall f a b. Applicative f => (a -> b) -> f a -> f b +liftA1 f a = pure f <*> a + +-- | Perform a applicative action when a condition is true. +when :: forall m. Applicative m => Boolean -> m Unit -> m Unit +when true m = m +when false _ = pure unit + +-- | Perform a applicative action unless a condition is true. +unless :: forall m. Applicative m => Boolean -> m Unit -> m Unit +unless false m = m +unless true _ = pure unit diff --git a/src/Control/Apply.js b/src/Control/Apply.js new file mode 100644 index 00000000..16a351a4 --- /dev/null +++ b/src/Control/Apply.js @@ -0,0 +1,16 @@ +"use strict"; + +// module Control.Apply + +exports.arrayApply = function (fs) { + return function (xs) { + var result = []; + var n = 0; + for (var i = 0, l = fs.length; i < l; i++) { + for (var j = 0, k = xs.length; j < k; j++) { + result[n++] = fs[i](xs[j]); + } + } + return result; + }; +}; diff --git a/src/Control/Apply.purs b/src/Control/Apply.purs new file mode 100644 index 00000000..e6e7e1d8 --- /dev/null +++ b/src/Control/Apply.purs @@ -0,0 +1,78 @@ +module Control.Apply + ( class Apply, apply, (<*>) + , applyFirst, (<*) + , applySecond, (*>) + , lift2, lift3, lift4, lift5 + , module Data.Functor + ) where + +import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) +import Data.Function (const) +import Control.Category (id) + +-- | The `Apply` class provides the `(<*>)` which is used to apply a function +-- | to an argument under a type constructor. +-- | +-- | `Apply` can be used to lift functions of two or more arguments to work on +-- | values wrapped with the type constructor `f`. It might also be understood +-- | in terms of the `lift2` function: +-- | +-- | ```purescript +-- | lift2 :: forall f a b c. Apply f => (a -> b -> c) -> f a -> f b -> f c +-- | lift2 f a b = f <$> a <*> b +-- | ``` +-- | +-- | `(<*>)` is recovered from `lift2` as `lift2 ($)`. That is, `(<*>)` lifts +-- | the function application operator `($)` to arguments wrapped with the +-- | type constructor `f`. +-- | +-- | Instances must satisfy the following law in addition to the `Functor` +-- | laws: +-- | +-- | - Associative composition: `(<<<) <$> f <*> g <*> h = f <*> (g <*> h)` +-- | +-- | Formally, `Apply` represents a strong lax semi-monoidal endofunctor. +class Functor f <= Apply f where + apply :: forall a b. f (a -> b) -> f a -> f b + +infixl 4 apply as <*> + +instance applyFn :: Apply ((->) r) where + apply f g x = f x (g x) + +instance applyArray :: Apply Array where + apply = arrayApply + +foreign import arrayApply :: forall a b. Array (a -> b) -> Array a -> Array b + +-- | Combine two effectful actions, keeping only the result of the first. +applyFirst :: forall a b f. Apply f => f a -> f b -> f a +applyFirst a b = const <$> a <*> b + +infixl 4 applyFirst as <* + +-- | Combine two effectful actions, keeping only the result of the second. +applySecond :: forall a b f. Apply f => f a -> f b -> f b +applySecond a b = const id <$> a <*> b + +infixl 4 applySecond as *> + +-- | Lift a function of two arguments to a function which accepts and returns +-- | values wrapped with the type constructor `f`. +lift2 :: forall a b c f. Apply f => (a -> b -> c) -> f a -> f b -> f c +lift2 f a b = f <$> a <*> b + +-- | Lift a function of three arguments to a function which accepts and returns +-- | values wrapped with the type constructor `f`. +lift3 :: forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d +lift3 f a b c = f <$> a <*> b <*> c + +-- | Lift a function of four arguments to a function which accepts and returns +-- | values wrapped with the type constructor `f`. +lift4 :: forall a b c d e f. Apply f => (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e +lift4 f a b c d = f <$> a <*> b <*> c <*> d + +-- | Lift a function of five arguments to a function which accepts and returns +-- | values wrapped with the type constructor `f`. +lift5 :: forall a b c d e f g. Apply f => (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g +lift5 f a b c d e = f <$> a <*> b <*> c <*> d <*> e diff --git a/src/Control/Bind.js b/src/Control/Bind.js new file mode 100644 index 00000000..d0e09d4f --- /dev/null +++ b/src/Control/Bind.js @@ -0,0 +1,13 @@ +"use strict"; + +// module Control.Bind + +exports.arrayBind = function (arr) { + return function (f) { + var result = []; + for (var i = 0, l = arr.length; i < l; i++) { + Array.prototype.push.apply(result, f(arr[i])); + } + return result; + }; +}; diff --git a/src/Control/Bind.purs b/src/Control/Bind.purs new file mode 100644 index 00000000..1b045aa9 --- /dev/null +++ b/src/Control/Bind.purs @@ -0,0 +1,103 @@ +module Control.Bind + ( class Bind, bind, (>>=) + , bindFlipped, (=<<) + , join + , composeKleisli, (>=>) + , composeKleisliFlipped, (<=<) + , ifM + , module Data.Functor + , module Control.Apply + , module Control.Applicative + ) where + +import Control.Applicative (class Applicative, liftA1, pure, unless, when) +import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) +import Control.Category (id) + +import Data.Function (flip) +import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) + +-- | The `Bind` type class extends the [`Apply`](#apply) type class with a +-- | "bind" operation `(>>=)` which composes computations in sequence, using +-- | the return value of one computation to determine the next computation. +-- | +-- | The `>>=` operator can also be expressed using `do` notation, as follows: +-- | +-- | ```purescript +-- | x >>= f = do y <- x +-- | f y +-- | ``` +-- | +-- | where the function argument of `f` is given the name `y`. +-- | +-- | Instances must satisfy the following law in addition to the `Apply` +-- | laws: +-- | +-- | - Associativity: `(x >>= f) >>= g = x >>= (\k => f k >>= g)` +-- | +-- | Associativity tells us that we can regroup operations which use `do` +-- | notation so that we can unambiguously write, for example: +-- | +-- | ```purescript +-- | do x <- m1 +-- | y <- m2 x +-- | m3 x y +-- | ``` +class Apply m <= Bind m where + bind :: forall a b. m a -> (a -> m b) -> m b + +infixl 1 bind as >>= + +-- | `bindFlipped` is `bind` with its arguments reversed. For example: +-- | +-- | ```purescript +-- | print =<< random +-- | ``` +bindFlipped :: forall m a b. Bind m => (a -> m b) -> m a -> m b +bindFlipped = flip bind + +infixl 1 bindFlipped as =<< + +instance bindFn :: Bind ((->) r) where + bind m f x = f (m x) x + +instance bindArray :: Bind Array where + bind = arrayBind + +foreign import arrayBind :: forall a b. Array a -> (a -> Array b) -> Array b + +-- | Collapse two applications of a monadic type constructor into one. +join :: forall a m. Bind m => m (m a) -> m a +join m = m >>= id + +-- | Forwards Kleisli composition. +-- | +-- | For example: +-- | +-- | ```purescript +-- | import Data.Array (head, tail) +-- | +-- | third = tail >=> tail >=> head +-- | ``` +composeKleisli :: forall a b c m. Bind m => (a -> m b) -> (b -> m c) -> a -> m c +composeKleisli f g a = f a >>= g + +infixr 1 composeKleisli as >=> + +-- | Backwards Kleisli composition. +composeKleisliFlipped :: forall a b c m. Bind m => (b -> m c) -> (a -> m b) -> a -> m c +composeKleisliFlipped f g a = f =<< g a + +infixr 1 composeKleisliFlipped as <=< + +-- | Execute a monadic action if a condition holds. +-- | +-- | For example: +-- | +-- | ```purescript +-- | main = ifM ((< 0.5) <$> random) +-- | (trace "Heads") +-- | (trace "Tails") +-- | ``` +ifM :: forall a m. Bind m => m Boolean -> m a -> m a -> m a +ifM cond t f = cond >>= \cond' -> if cond' then t else f diff --git a/src/Control/Category.purs b/src/Control/Category.purs new file mode 100644 index 00000000..9fa17b23 --- /dev/null +++ b/src/Control/Category.purs @@ -0,0 +1,20 @@ +module Control.Category + ( class Category, id + , module Control.Semigroupoid + ) where + +import Control.Semigroupoid (class Semigroupoid, compose, (<<<), (>>>)) + +-- | `Category`s consist of objects and composable morphisms between them, and +-- | as such are [`Semigroupoids`](#semigroupoid), but unlike `semigroupoids` +-- | must have an identity element. +-- | +-- | Instances must satisfy the following law in addition to the +-- | `Semigroupoid` law: +-- | +-- | - Identity: `id <<< p = p <<< id = p` +class Semigroupoid a <= Category a where + id :: forall t. a t t + +instance categoryFn :: Category (->) where + id x = x diff --git a/src/Control/Monad.purs b/src/Control/Monad.purs new file mode 100644 index 00000000..b548721d --- /dev/null +++ b/src/Control/Monad.purs @@ -0,0 +1,63 @@ +module Control.Monad + ( class Monad + , liftM1 + , ap + , module Data.Functor + , module Control.Apply + , module Control.Applicative + , module Control.Bind + ) where + +import Control.Applicative (class Applicative, liftA1, pure, unless, when) +import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) +import Control.Bind (class Bind, bind, ifM, join, (<=<), (=<<), (>=>), (>>=)) + +import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) + +-- | The `Monad` type class combines the operations of the `Bind` and +-- | `Applicative` type classes. Therefore, `Monad` instances represent type +-- | constructors which support sequential composition, and also lifting of +-- | functions of arbitrary arity. +-- | +-- | Instances must satisfy the following laws in addition to the +-- | `Applicative` and `Bind` laws: +-- | +-- | - Left Identity: `pure x >>= f = f x` +-- | - Right Identity: `x >>= pure = x` +class (Applicative m, Bind m) <= Monad m + +instance monadFn :: Monad ((->) r) +instance monadArray :: Monad Array + +-- | `liftM1` provides a default implementation of `(<$>)` for any +-- | [`Monad`](#monad), without using `(<$>)` as provided by the +-- | [`Functor`](#functor)-[`Monad`](#monad) superclass relationship. +-- | +-- | `liftM1` can therefore be used to write [`Functor`](#functor) instances +-- | as follows: +-- | +-- | ```purescript +-- | instance functorF :: Functor F where +-- | map = liftM1 +-- | ``` +liftM1 :: forall m a b. Monad m => (a -> b) -> m a -> m b +liftM1 f a = do + a' <- a + pure (f a') + +-- | `ap` provides a default implementation of `(<*>)` for any +-- | [`Monad`](#monad), without using `(<*>)` as provided by the +-- | [`Apply`](#apply)-[`Monad`](#monad) superclass relationship. +-- | +-- | `ap` can therefore be used to write [`Apply`](#apply) instances as +-- | follows: +-- | +-- | ```purescript +-- | instance applyF :: Apply F where +-- | apply = ap +-- | ``` +ap :: forall m a b. Monad m => m (a -> b) -> m a -> m b +ap f a = do + f' <- f + a' <- a + pure (f' a') diff --git a/src/Control/Semigroupoid.purs b/src/Control/Semigroupoid.purs new file mode 100644 index 00000000..729e1bbe --- /dev/null +++ b/src/Control/Semigroupoid.purs @@ -0,0 +1,24 @@ +module Control.Semigroupoid where + +-- | A `Semigroupoid` is similar to a [`Category`](#category) but does not +-- | require an identity element `id`, just composable morphisms. +-- | +-- | `Semigroupoid`s must satisfy the following law: +-- | +-- | - Associativity: `p <<< (q <<< r) = (p <<< q) <<< r` +-- | +-- | One example of a `Semigroupoid` is the function type constructor `(->)`, +-- | with `(<<<)` defined as function composition. +class Semigroupoid a where + compose :: forall b c d. a c d -> a b c -> a b d + +instance semigroupoidFn :: Semigroupoid (->) where + compose f g x = f (g x) + +infixr 9 compose as <<< + +-- | Forwards composition, or `compose` with its arguments reversed. +composeFlipped :: forall a b c d. Semigroupoid a => a b c -> a c d -> a b d +composeFlipped f g = compose g f + +infixr 9 composeFlipped as >>> diff --git a/src/Data/Boolean.purs b/src/Data/Boolean.purs new file mode 100644 index 00000000..9b4f6909 --- /dev/null +++ b/src/Data/Boolean.purs @@ -0,0 +1,10 @@ +module Data.Boolean where + +-- | An alias for `true`, which can be useful in guard clauses: +-- | +-- | ```purescript +-- | max x y | x >= y = x +-- | | otherwise = y +-- | ``` +otherwise :: Boolean +otherwise = true diff --git a/src/Data/BooleanAlgebra.js b/src/Data/BooleanAlgebra.js new file mode 100644 index 00000000..153f4f76 --- /dev/null +++ b/src/Data/BooleanAlgebra.js @@ -0,0 +1,19 @@ +"use strict"; + +// module Data.BooleanAlgebra + +exports.boolConj = function (b1) { + return function (b2) { + return b1 && b2; + }; +}; + +exports.boolDisj = function (b1) { + return function (b2) { + return b1 || b2; + }; +}; + +exports.boolNot = function (b) { + return !b; +}; diff --git a/src/Data/BooleanAlgebra.purs b/src/Data/BooleanAlgebra.purs new file mode 100644 index 00000000..81d25df8 --- /dev/null +++ b/src/Data/BooleanAlgebra.purs @@ -0,0 +1,63 @@ +module Data.BooleanAlgebra + ( class BooleanAlgebra, conj, disj, not + , (&&), (||) + ) where + +import Data.Bounded (class Bounded) +import Data.Unit (Unit, unit) + +-- | The `BooleanAlgebra` type class represents types that behave like boolean +-- | values. +-- | +-- | Instances should satisfy the following laws in addition to the `Bounded` +-- | laws: +-- | +-- | - Associativity: +-- | - `a || (b || c) = (a || b) || c` +-- | - `a && (b && c) = (a && b) && c` +-- | - Commutativity: +-- | - `a || b = b || a` +-- | - `a && b = b && a` +-- | - Distributivity: +-- | - `a && (b || c) = (a && b) || (a && c)` +-- | - `a || (b && c) = (a || b) && (a || c)` +-- | - Identity: +-- | - `a || bottom = a` +-- | - `a && top = a` +-- | - Idempotent: +-- | - `a || a = a` +-- | - `a && a = a` +-- | - Absorption: +-- | - `a || (a && b) = a` +-- | - `a && (a || b) = a` +-- | - Annhiliation: +-- | - `a || top = top` +-- | - Complementation: +-- | - `a && not a = bottom` +-- | - `a || not a = top` +class Bounded a <= BooleanAlgebra a where + conj :: a -> a -> a + disj :: a -> a -> a + not :: a -> a + +infixr 3 conj as && +infixr 2 disj as || + +instance booleanAlgebraBoolean :: BooleanAlgebra Boolean where + conj = boolConj + disj = boolDisj + not = boolNot + +instance booleanAlgebraUnit :: BooleanAlgebra Unit where + conj _ _ = unit + disj _ _ = unit + not _ = unit + +instance booleanAlgebraFn :: BooleanAlgebra b => BooleanAlgebra (a -> b) where + conj fx fy a = fx a `conj` fy a + disj fx fy a = fx a `disj` fy a + not fx a = not (fx a) + +foreign import boolConj :: Boolean -> Boolean -> Boolean +foreign import boolDisj :: Boolean -> Boolean -> Boolean +foreign import boolNot :: Boolean -> Boolean diff --git a/src/Data/Bounded.js b/src/Data/Bounded.js new file mode 100644 index 00000000..c4b028f8 --- /dev/null +++ b/src/Data/Bounded.js @@ -0,0 +1,9 @@ +"use strict"; + +// module Data.Bounded + +exports.topInt = 2147483647; +exports.bottomInt = -2147483648; + +exports.topChar = String.fromCharCode(65535); +exports.bottomChar = String.fromCharCode(0); diff --git a/src/Data/Bounded.purs b/src/Data/Bounded.purs new file mode 100644 index 00000000..7961e674 --- /dev/null +++ b/src/Data/Bounded.purs @@ -0,0 +1,44 @@ +module Data.Bounded (class Bounded, bottom, top) where + +import Data.Unit (Unit, unit) + +-- | The `Bounded` type class represents types that have an upper and lower +-- | boundary. +-- | +-- | Although there are no "internal" laws for `Bounded`, every value of `a` +-- | should be considered less than or equal to `top` by some means, and greater +-- | than or equal to `bottom`. +-- | +-- | The lack of explicit `Ord` constraint allows flexibility in the use of +-- | `Bounded` so it can apply to total and partially ordered sets, boolean +-- | algebras, etc. +class Bounded a where + top :: a + bottom :: a + +instance boundedBoolean :: Bounded Boolean where + top = true + bottom = false + +instance boundedInt :: Bounded Int where + top = topInt + bottom = bottomInt + +foreign import topInt :: Int +foreign import bottomInt :: Int + +-- | Characters fall within the Unicode range. +instance boundedChar :: Bounded Char where + top = topChar + bottom = bottomChar + +foreign import topChar :: Char +foreign import bottomChar :: Char + +instance boundedUnit :: Bounded Unit where + top = unit + bottom = unit + +instance boundedFn :: Bounded b => Bounded (a -> b) where + top _ = top + bottom _ = bottom diff --git a/src/Data/BoundedOrd.purs b/src/Data/BoundedOrd.purs new file mode 100644 index 00000000..b3552d00 --- /dev/null +++ b/src/Data/BoundedOrd.purs @@ -0,0 +1,24 @@ +module Data.BoundedOrd + ( class BoundedOrd + , module Data.Bounded + , module Data.Ord + ) where + +import Data.Bounded (class Bounded, bottom, top) +import Data.Ord (class Ord, Ordering(..), compare, (<), (<=), (>), (>=)) +import Data.Unit (Unit) + +-- | The `BoundedOrd` type class represents types with an upper and lower +-- | boundary and that are totally ordered. +-- | +-- | Instances should satisfy the following law in addition to the `Ord` laws: +-- | +-- | - Ordering: `bottom <= a <= top` +class (Bounded a, Ord a) <= BoundedOrd a + +instance boundedOrdBoolean :: BoundedOrd Boolean where +instance boundedOrdInt :: BoundedOrd Int where +instance boundedOrdChar :: BoundedOrd Char where +instance boundedOrdUnit :: BoundedOrd Unit where +instance boundedOrdOrdering :: BoundedOrd Ordering where + diff --git a/src/Data/DivisionRing.purs b/src/Data/DivisionRing.purs new file mode 100644 index 00000000..d9ddf7a1 --- /dev/null +++ b/src/Data/DivisionRing.purs @@ -0,0 +1,25 @@ +module Data.DivisionRing + ( class DivisionRing + , module Data.ModuloSemiring + , module Data.Ring + , module Data.Semiring + ) where + +import Data.ModuloSemiring (class ModuloSemiring, div, mod, (/)) +import Data.Ring (class Ring, negate, sub) +import Data.Semiring (class Semiring, add, mul, one, zero, (*), (+)) +import Data.Unit (Unit) + +-- | A `Ring` where every nonzero element has a multiplicative inverse. +-- | +-- | Instances must satisfy the following law in addition to the `Ring` and +-- | `ModuloSemiring` laws: +-- | +-- | - Multiplicative inverse: `(one / x) * x = one` +-- | +-- | As a consequence of this ```a `mod` b = zero``` as no divide operation +-- | will have a remainder. +class (Ring a, ModuloSemiring a) <= DivisionRing a + +instance divisionRingNumber :: DivisionRing Number +instance divisionRingUnit :: DivisionRing Unit diff --git a/src/Data/Eq.js b/src/Data/Eq.js new file mode 100644 index 00000000..16c7c671 --- /dev/null +++ b/src/Data/Eq.js @@ -0,0 +1,27 @@ +"use strict"; + +// module Data.Eq + +exports.refEq = function (r1) { + return function (r2) { + return r1 === r2; + }; +}; + +exports.refIneq = function (r1) { + return function (r2) { + return r1 !== r2; + }; +}; + +exports.eqArrayImpl = function (f) { + return function (xs) { + return function (ys) { + if (xs.length !== ys.length) return false; + for (var i = 0; i < xs.length; i++) { + if (!f(xs[i])(ys[i])) return false; + } + return true; + }; + }; +}; diff --git a/src/Data/Eq.purs b/src/Data/Eq.purs new file mode 100644 index 00000000..33d4a7e1 --- /dev/null +++ b/src/Data/Eq.purs @@ -0,0 +1,51 @@ +module Data.Eq (class Eq, eq, (==), notEq, (/=)) where + +import Data.Unit (Unit) +import Data.Void (Void) + +-- | The `Eq` type class represents types which support decidable equality. +-- | +-- | `Eq` instances should satisfy the following laws: +-- | +-- | - Reflexivity: `x == x = true` +-- | - Symmetry: `x == y = y == x` +-- | - Transitivity: if `x == y` and `y == z` then `x == z` +class Eq a where + eq :: a -> a -> Boolean + +infix 4 eq as == + +-- | `notEq` tests whether one value is _not equal_ to another. Shorthand for +-- | `not (eq x y)`. +notEq :: forall a. Eq a => a -> a -> Boolean +notEq x y = (x == y) == false + +infix 4 notEq as /= + +instance eqBoolean :: Eq Boolean where + eq = refEq + +instance eqInt :: Eq Int where + eq = refEq + +instance eqNumber :: Eq Number where + eq = refEq + +instance eqChar :: Eq Char where + eq = refEq + +instance eqString :: Eq String where + eq = refEq + +instance eqUnit :: Eq Unit where + eq _ _ = true + +instance eqVoid :: Eq Void where + eq _ _ = true + +instance eqArray :: Eq a => Eq (Array a) where + eq = eqArrayImpl eq + +foreign import refEq :: forall a. a -> a -> Boolean +foreign import refIneq :: forall a. a -> a -> Boolean +foreign import eqArrayImpl :: forall a. (a -> a -> Boolean) -> Array a -> Array a -> Boolean diff --git a/src/Data/Function.purs b/src/Data/Function.purs new file mode 100644 index 00000000..f3f067d9 --- /dev/null +++ b/src/Data/Function.purs @@ -0,0 +1,89 @@ +module Data.Function + ( flip + , const + , apply, ($) + , applyFlipped, (#) + , on + , module Control.Category + ) where + +import Control.Category (id, compose, (<<<), (>>>)) + +-- | Flips the order of the arguments to a function of two arguments. +-- | +-- | ```purescript +-- | flip const 1 2 = const 2 1 = 2 +-- | ``` +flip :: forall a b c. (a -> b -> c) -> b -> a -> c +flip f b a = f a b + +-- | Returns its first argument and ignores its second. +-- | +-- | ```purescript +-- | const 1 "hello" = 1 +-- | ``` +const :: forall a b. a -> b -> a +const a _ = a + +-- | Applies a function to an argument. This is primarily used as the operator +-- | `($)` which allows parentheses to be omitted in some cases, or as a +-- | natural way to apply a chain of composed functions to a value. +apply :: forall a b. (a -> b) -> a -> b +apply f x = f x + +-- | Applies a function to an argument: the reverse of `(#)`. +-- | +-- | ```purescript +-- | length $ groupBy productCategory $ filter isInStock $ products +-- | ``` +-- | +-- | is equivalent to: +-- | +-- | ```purescript +-- | length (groupBy productCategory (filter isInStock products)) +-- | ``` +-- | +-- | Or another alternative equivalent, applying chain of composed functions to +-- | a value: +-- | +-- | ```purescript +-- | length <<< groupBy productCategory <<< filter isInStock $ products +-- | ``` +infixr 0 apply as $ + +-- | Applies an argument to a function. This is primarily used as the `(#)` +-- | operator, which allows parentheses to be ommitted in some cases, or as a +-- | natural way to apply a value to a chain of composed functions. +applyFlipped :: forall a b. a -> (a -> b) -> b +applyFlipped x f = f x + +-- | Applies an argument to a function: the reverse of `($)`. +-- | +-- | ```purescript +-- | products # filter isInStock # groupBy productCategory # length +-- | ``` +-- | +-- | is equivalent to: +-- | +-- | ```purescript +-- | length (groupBy productCategory (filter isInStock products)) +-- | ``` +-- | +-- | Or another alternative equivalent, applying a value to a chain of composed +-- | functions: +-- | +-- | ```purescript +-- | products # filter isInStock >>> groupBy productCategory >>> length +-- | ``` +infixl 1 applyFlipped as # + +-- | The `on` function is used to change the domain of a binary operator. +-- | +-- | For example, we can create a function which compares two records based on the values of their `x` properties: +-- | +-- | ```purescript +-- | compareX :: forall r. { x :: Number | r } -> { x :: Number | r } -> Ordering +-- | compareX = compare `on` _.x +-- | ``` +on :: forall a b c. (b -> b -> c) -> (a -> b) -> a -> a -> c +on f g x y = g x `f` g y diff --git a/src/Data/Functor.js b/src/Data/Functor.js new file mode 100644 index 00000000..96f11fd1 --- /dev/null +++ b/src/Data/Functor.js @@ -0,0 +1,14 @@ +"use strict"; + +// module Data.Functor + +exports.arrayMap = function (f) { + return function (arr) { + var l = arr.length; + var result = new Array(l); + for (var i = 0; i < l; i++) { + result[i] = f(arr[i]); + } + return result; + }; +}; diff --git a/src/Data/Functor.purs b/src/Data/Functor.purs new file mode 100644 index 00000000..782e1dc2 --- /dev/null +++ b/src/Data/Functor.purs @@ -0,0 +1,72 @@ +module Data.Functor + ( class Functor, map, (<$>) + , mapFlipped, (<#>) + , void + , voidRight, (<$) + , voidLeft, ($>) + ) where + +import Data.Function (const, compose) +import Data.Unit (Unit, unit) + +-- | A `Functor` is a type constructor which supports a mapping operation +-- | `(<$>)`. +-- | +-- | `(<$>)` can be used to turn functions `a -> b` into functions +-- | `f a -> f b` whose argument and return types use the type constructor `f` +-- | to represent some computational context. +-- | +-- | Instances must satisfy the following laws: +-- | +-- | - Identity: `(<$>) id = id` +-- | - Composition: `(<$>) (f <<< g) = (f <$>) <<< (g <$>)` +class Functor f where + map :: forall a b. (a -> b) -> f a -> f b + +infixl 4 map as <$> + +-- | `mapFlipped` is `map` with its arguments reversed. For example: +-- | +-- | ```purescript +-- | [1, 2, 3] <#> \n -> n * n +-- | ``` +mapFlipped :: forall f a b. Functor f => f a -> (a -> b) -> f b +mapFlipped fa f = f <$> fa + +infixl 1 mapFlipped as <#> + +instance functorFn :: Functor ((->) r) where + map = compose + +instance functorArray :: Functor Array where + map = arrayMap + +foreign import arrayMap :: forall a b. (a -> b) -> Array a -> Array b + +-- | The `void` function is used to ignore the type wrapped by a +-- | [`Functor`](#functor), replacing it with `Unit` and keeping only the type +-- | information provided by the type constructor itself. +-- | +-- | `void` is often useful when using `do` notation to change the return type +-- | of a monadic computation: +-- | +-- | ```purescript +-- | main = forE 1 10 \n -> void do +-- | print n +-- | print (n * n) +-- | ``` +void :: forall f a. Functor f => f a -> f Unit +void = map (const unit) + +-- | Ignore the return value of a computation, using the specified return value +-- | instead. +voidRight :: forall f a b. Functor f => a -> f b -> f a +voidRight x = map (const x) + +infixl 4 voidRight as <$ + +-- | A version of `voidLast` with its arguments flipped. +voidLeft :: forall f a b. Functor f => f a -> b -> f b +voidLeft f x = const x <$> f + +infixl 4 voidLeft as $> diff --git a/src/Data/ModuloSemiring.js b/src/Data/ModuloSemiring.js new file mode 100644 index 00000000..70d6e851 --- /dev/null +++ b/src/Data/ModuloSemiring.js @@ -0,0 +1,22 @@ +"use strict"; + +// module Data.ModuloSemiring + +exports.intDiv = function (x) { + return function (y) { + /* jshint bitwise: false */ + return x / y | 0; + }; +}; + +exports.intMod = function (x) { + return function (y) { + return x % y; + }; +}; + +exports.numDiv = function (n1) { + return function (n2) { + return n1 / n2; + }; +}; diff --git a/src/Data/ModuloSemiring.purs b/src/Data/ModuloSemiring.purs new file mode 100644 index 00000000..ff499722 --- /dev/null +++ b/src/Data/ModuloSemiring.purs @@ -0,0 +1,37 @@ +module Data.ModuloSemiring + ( class ModuloSemiring, div, mod, (/) + , module Data.Semiring + ) where + +import Data.Semiring (class Semiring, add, mul, one, zero, (*), (+)) +import Data.Unit (Unit, unit) +import Data.Void (Void) + +-- | The `ModuloSemiring` class is for types that support addition, +-- | multiplication, division, and modulo (division remainder) operations. +-- | +-- | Instances must satisfy the following law in addition to the `Semiring` +-- | laws: +-- | +-- | - Remainder: ``a / b * b + (a `mod` b) = a`` +class Semiring a <= ModuloSemiring a where + div :: a -> a -> a + mod :: a -> a -> a + +infixl 7 div as / + +instance moduloSemiringInt :: ModuloSemiring Int where + div = intDiv + mod = intMod + +instance moduloSemiringNumber :: ModuloSemiring Number where + div = numDiv + mod _ _ = 0.0 + +instance moduloSemiringUnit :: ModuloSemiring Unit where + div _ _ = unit + mod _ _ = unit + +foreign import intDiv :: Int -> Int -> Int +foreign import numDiv :: Number -> Number -> Number +foreign import intMod :: Int -> Int -> Int diff --git a/src/Data/Num.purs b/src/Data/Num.purs new file mode 100644 index 00000000..ef193c5c --- /dev/null +++ b/src/Data/Num.purs @@ -0,0 +1,24 @@ +module Data.Num + ( class Num + , module Data.DivisionRing + , module Data.ModuloSemiring + , module Data.Ring + , module Data.Semiring + ) where + +import Data.ModuloSemiring (class ModuloSemiring, div, mod, (/)) +import Data.Ring (class Ring, negate, sub) +import Data.Semiring (class Semiring, add, mul, one, zero, (*), (+)) +import Data.DivisionRing (class DivisionRing) +import Data.Unit (Unit) + +-- | The `Num` class is for types that are commutative fields. +-- | +-- | Instances must satisfy the following law in addition to the +-- | `DivisionRing` laws: +-- | +-- | - Commutative multiplication: `a * b = b * a` +class DivisionRing a <= Num a + +instance numNumber :: Num Number +instance numUnit :: Num Unit diff --git a/src/Data/Ord.js b/src/Data/Ord.js new file mode 100644 index 00000000..ad8306fc --- /dev/null +++ b/src/Data/Ord.js @@ -0,0 +1,41 @@ +"use strict"; + +// module Data.Ord + +exports.ordArrayImpl = function (f) { + return function (xs) { + return function (ys) { + var i = 0; + var xlen = xs.length; + var ylen = ys.length; + while (i < xlen && i < ylen) { + var x = xs[i]; + var y = ys[i]; + var o = f(x)(y); + if (o !== 0) { + return o; + } + i++; + } + if (xlen === ylen) { + return 0; + } else if (xlen > ylen) { + return -1; + } else { + return 1; + } + }; + }; +}; + +exports.unsafeCompareImpl = function (lt) { + return function (eq) { + return function (gt) { + return function (x) { + return function (y) { + return x < y ? lt : x > y ? gt : eq; + }; + }; + }; + }; +}; diff --git a/src/Data/Ord.purs b/src/Data/Ord.purs new file mode 100644 index 00000000..d4025758 --- /dev/null +++ b/src/Data/Ord.purs @@ -0,0 +1,150 @@ +module Data.Ord + ( class Ord, compare + , lessThan, (<) + , lessThanOrEq, (<=) + , greaterThan, (>) + , greaterThanOrEq, (>=) + , comparing + , min, max + , clamp + , between + , module Data.Ordering + ) where + +import Data.Bounded (class Bounded) +import Data.Eq (class Eq) +import Data.Function (on) +import Data.Ord.Unsafe (unsafeCompare) +import Data.Ordering (Ordering(..)) +import Data.Ring (negate) +import Data.Semigroup (class Semigroup) +import Data.Show (class Show) +import Data.Unit (Unit) + +-- | The `Ord` type class represents types which support comparisons with a +-- | _total order_. +-- | +-- | `Ord` instances should satisfy the laws of total orderings: +-- | +-- | - Reflexivity: `a <= a` +-- | - Antisymmetry: if `a <= b` and `b <= a` then `a = b` +-- | - Transitivity: if `a <= b` and `b <= c` then `a <= c` +class Eq a <= Ord a where + compare :: a -> a -> Ordering + +instance ordBoolean :: Ord Boolean where + compare = unsafeCompare + +instance ordInt :: Ord Int where + compare = unsafeCompare + +instance ordNumber :: Ord Number where + compare = unsafeCompare + +instance ordString :: Ord String where + compare = unsafeCompare + +instance ordChar :: Ord Char where + compare = unsafeCompare + +instance ordUnit :: Ord Unit where + compare _ _ = EQ + +instance ordArray :: Ord a => Ord (Array a) where + compare = \xs ys -> compare 0 (ordArrayImpl toDelta xs ys) + where + toDelta x y = + case compare x y of + EQ -> 0 + LT -> 1 + GT -> -1 + +foreign import ordArrayImpl :: forall a. (a -> a -> Int) -> Array a -> Array a -> Int + +instance ordOrdering :: Ord Ordering where + compare LT LT = EQ + compare EQ EQ = EQ + compare GT GT = EQ + compare LT _ = LT + compare EQ LT = GT + compare EQ GT = LT + compare GT _ = GT + +-- | Test whether one value is _strictly less than_ another. +lessThan :: forall a. Ord a => a -> a -> Boolean +lessThan a1 a2 = case a1 `compare` a2 of + LT -> true + _ -> false + +-- | Test whether one value is _strictly greater than_ another. +greaterThan :: forall a. Ord a => a -> a -> Boolean +greaterThan a1 a2 = case a1 `compare` a2 of + GT -> true + _ -> false + +-- | Test whether one value is _non-strictly less than_ another. +lessThanOrEq :: forall a. Ord a => a -> a -> Boolean +lessThanOrEq a1 a2 = case a1 `compare` a2 of + GT -> false + _ -> true + +-- | Test whether one value is _non-strictly greater than_ another. +greaterThanOrEq :: forall a. Ord a => a -> a -> Boolean +greaterThanOrEq a1 a2 = case a1 `compare` a2 of + LT -> false + _ -> true + +infixl 4 lessThan as < +infixl 4 lessThanOrEq as <= +infixl 4 greaterThan as > +infixl 4 greaterThanOrEq as >= + +-- | Compares two values by mapping them to a type with an `Ord` instance. +comparing :: forall a b. Ord b => (a -> b) -> (a -> a -> Ordering) +comparing f = compare `on` f + +-- | Take the minimum of two values. If they are considered equal, the first +-- | argument is chosen. +min :: forall a. Ord a => a -> a -> a +min x y = + case compare x y of + LT -> x + EQ -> x + GT -> y + +-- | Take the maximum of two values. If they are considered equal, the first +-- | argument is chosen. +max :: forall a. Ord a => a -> a -> a +max x y = + case compare x y of + LT -> y + EQ -> x + GT -> x + +-- | Clamp a value between a minimum and a maximum. For example: +-- | +-- | ``` purescript +-- | let f = clamp 0 10 +-- | f (-5) == 0 +-- | f 5 == 5 +-- | f 15 == 10 +-- | ``` +clamp :: forall a. Ord a => a -> a -> a -> a +clamp low hi x = min hi (max low x) + +-- | Test whether a value is between a minimum and a maximum (inclusive). +-- | For example: +-- | +-- | ``` purescript +-- | let f = between 0 10 +-- | f 0 == true +-- | f (-5) == false +-- | f 5 == true +-- | f 10 == true +-- | f 15 == false +-- | ``` +between :: forall a. Ord a => a -> a -> a -> Boolean +between low hi x + | x < low = false + | x > hi = false + | true = true diff --git a/src/Data/Ord/Unsafe.js b/src/Data/Ord/Unsafe.js new file mode 100644 index 00000000..229c0058 --- /dev/null +++ b/src/Data/Ord/Unsafe.js @@ -0,0 +1,15 @@ +"use strict"; + +// module Data.Ord.Unsafe + +exports.unsafeCompareImpl = function (lt) { + return function (eq) { + return function (gt) { + return function (x) { + return function (y) { + return x < y ? lt : x > y ? gt : eq; + }; + }; + }; + }; +}; diff --git a/src/Data/Ord/Unsafe.purs b/src/Data/Ord/Unsafe.purs new file mode 100644 index 00000000..dcb30401 --- /dev/null +++ b/src/Data/Ord/Unsafe.purs @@ -0,0 +1,15 @@ +module Data.Ord.Unsafe (unsafeCompare) where + +import Data.Ordering (Ordering(..)) + +unsafeCompare :: forall a. a -> a -> Ordering +unsafeCompare = unsafeCompareImpl LT EQ GT + +foreign import unsafeCompareImpl + :: forall a + . Ordering + -> Ordering + -> Ordering + -> a + -> a + -> Ordering diff --git a/src/Data/Ordering.purs b/src/Data/Ordering.purs new file mode 100644 index 00000000..e984983d --- /dev/null +++ b/src/Data/Ordering.purs @@ -0,0 +1,41 @@ +module Data.Ordering (Ordering(..), invert) where + +import Data.Bounded (class Bounded) +import Data.Eq (class Eq) +import Data.Semigroup (class Semigroup) +import Data.Show (class Show) + +-- | The `Ordering` data type represents the three possible outcomes of +-- | comparing two values: +-- | +-- | `LT` - The first value is _less than_ the second. +-- | `GT` - The first value is _greater than_ the second. +-- | `EQ` - The first value is _equal to_ the second. +data Ordering = LT | GT | EQ + +instance eqOrdering :: Eq Ordering where + eq LT LT = true + eq GT GT = true + eq EQ EQ = true + eq _ _ = false + +instance boundedOrdering :: Bounded Ordering where + top = GT + bottom = LT + +instance semigroupOrdering :: Semigroup Ordering where + append LT _ = LT + append GT _ = GT + append EQ y = y + +instance showOrdering :: Show Ordering where + show LT = "LT" + show GT = "GT" + show EQ = "EQ" + +-- | Reverses an `Ordering` value, flipping greater than for less than while +-- | preserving equality. +invert :: Ordering -> Ordering +invert GT = LT +invert EQ = EQ +invert LT = GT diff --git a/src/Data/Ring.js b/src/Data/Ring.js new file mode 100644 index 00000000..e9186dfc --- /dev/null +++ b/src/Data/Ring.js @@ -0,0 +1,16 @@ +"use strict"; + +// module Data.Ring + +exports.intSub = function (x) { + return function (y) { + /* jshint bitwise: false */ + return x - y | 0; + }; +}; + +exports.numSub = function (n1) { + return function (n2) { + return n1 - n2; + }; +}; diff --git a/src/Data/Ring.purs b/src/Data/Ring.purs new file mode 100644 index 00000000..3e988d81 --- /dev/null +++ b/src/Data/Ring.purs @@ -0,0 +1,35 @@ +module Data.Ring + ( class Ring, sub, negate, (-) + , module Data.Semiring + ) where + +import Data.Semiring (class Semiring, add, mul, one, zero, (*), (+)) +import Data.Unit (Unit, unit) + +-- | The `Ring` class is for types that support addition, multiplication, +-- | and subtraction operations. +-- | +-- | Instances must satisfy the following law in addition to the `Semiring` +-- | laws: +-- | +-- | - Additive inverse: `a - a = (zero - a) + a = zero` +class Semiring a <= Ring a where + sub :: a -> a -> a + +infixl 6 sub as - + +instance ringInt :: Ring Int where + sub = intSub + +instance ringNumber :: Ring Number where + sub = numSub + +instance ringUnit :: Ring Unit where + sub _ _ = unit + +-- | `negate x` can be used as a shorthand for `zero - x`. +negate :: forall a. Ring a => a -> a +negate a = zero - a + +foreign import intSub :: Int -> Int -> Int +foreign import numSub :: Number -> Number -> Number diff --git a/src/Data/Semigroup.js b/src/Data/Semigroup.js new file mode 100644 index 00000000..1075ce0d --- /dev/null +++ b/src/Data/Semigroup.js @@ -0,0 +1,15 @@ +"use strict"; + +// module Data.Semigroup + +exports.concatString = function (s1) { + return function (s2) { + return s1 + s2; + }; +}; + +exports.concatArray = function (xs) { + return function (ys) { + return xs.concat(ys); + }; +}; diff --git a/src/Data/Semigroup.purs b/src/Data/Semigroup.purs new file mode 100644 index 00000000..e8f75b77 --- /dev/null +++ b/src/Data/Semigroup.purs @@ -0,0 +1,31 @@ +module Data.Semigroup (class Semigroup, append, (<>)) where + +import Data.Unit (Unit, unit) + +-- | The `Semigroup` type class identifies an associative operation on a type. +-- | +-- | Instances are required to satisfy the following law: +-- | +-- | - Associativity: `(x <> y) <> z = x <> (y <> z)` +-- | +-- | One example of a `Semigroup` is `String`, with `(<>)` defined as string +-- | concatenation. +class Semigroup a where + append :: a -> a -> a + +infixr 5 append as <> + +instance semigroupString :: Semigroup String where + append = concatString + +instance semigroupUnit :: Semigroup Unit where + append _ _ = unit + +instance semigroupFn :: Semigroup s' => Semigroup (s -> s') where + append f g x = f x <> g x + +instance semigroupArray :: Semigroup (Array a) where + append = concatArray + +foreign import concatString :: String -> String -> String +foreign import concatArray :: forall a. Array a -> Array a -> Array a diff --git a/src/Data/Semiring.js b/src/Data/Semiring.js new file mode 100644 index 00000000..2ce2b3d5 --- /dev/null +++ b/src/Data/Semiring.js @@ -0,0 +1,29 @@ +"use strict"; + +// module Data.Semiring + +exports.intAdd = function (x) { + return function (y) { + /* jshint bitwise: false */ + return x + y | 0; + }; +}; + +exports.intMul = function (x) { + return function (y) { + /* jshint bitwise: false */ + return x * y | 0; + }; +}; + +exports.numAdd = function (n1) { + return function (n2) { + return n1 + n2; + }; +}; + +exports.numMul = function (n1) { + return function (n2) { + return n1 * n2; + }; +}; diff --git a/src/Data/Semiring.purs b/src/Data/Semiring.purs new file mode 100644 index 00000000..47ae41b5 --- /dev/null +++ b/src/Data/Semiring.purs @@ -0,0 +1,51 @@ +module Data.Semiring (class Semiring, add, (+), zero, mul, (*), one) where + +import Data.Unit (Unit, unit) + +-- | The `Semiring` class is for types that support an addition and +-- | multiplication operation. +-- | +-- | Instances must satisfy the following laws: +-- | +-- | - Commutative monoid under addition: +-- | - Associativity: `(a + b) + c = a + (b + c)` +-- | - Identity: `zero + a = a + zero = a` +-- | - Commutative: `a + b = b + a` +-- | - Monoid under multiplication: +-- | - Associativity: `(a * b) * c = a * (b * c)` +-- | - Identity: `one * a = a * one = a` +-- | - Multiplication distributes over addition: +-- | - Left distributivity: `a * (b + c) = (a * b) + (a * c)` +-- | - Right distributivity: `(a + b) * c = (a * c) + (b * c)` +-- | - Annihiliation: `zero * a = a * zero = zero` +class Semiring a where + add :: a -> a -> a + zero :: a + mul :: a -> a -> a + one :: a + +infixl 6 add as + +infixl 7 mul as * + +instance semiringInt :: Semiring Int where + add = intAdd + zero = 0 + mul = intMul + one = 1 + +instance semiringNumber :: Semiring Number where + add = numAdd + zero = 0.0 + mul = numMul + one = 1.0 + +instance semiringUnit :: Semiring Unit where + add _ _ = unit + zero = unit + mul _ _ = unit + one = unit + +foreign import intAdd :: Int -> Int -> Int +foreign import intMul :: Int -> Int -> Int +foreign import numAdd :: Number -> Number -> Number +foreign import numMul :: Number -> Number -> Number diff --git a/src/Data/Show.js b/src/Data/Show.js new file mode 100644 index 00000000..68bbe763 --- /dev/null +++ b/src/Data/Show.js @@ -0,0 +1,63 @@ +"use strict"; + +// module Data.Show + +exports.showIntImpl = function (n) { + return n.toString(); +}; + +exports.showNumberImpl = function (n) { + /* jshint bitwise: false */ + return n === (n | 0) ? n + ".0" : n.toString(); +}; + +exports.showCharImpl = function (c) { + var code = c.charCodeAt(0); + if (code < 0x20 || code === 0x7F) { + switch (c) { + case "\a": return "'\\a'"; + case "\b": return "'\\b'"; + case "\f": return "'\\f'"; + case "\n": return "'\\n'"; + case "\r": return "'\\r'"; + case "\t": return "'\\t'"; + case "\v": return "'\\v'"; + } + return "'\\" + code.toString(10) + "'"; + } + return c === "'" || c === "\\" ? "'\\" + c + "'" : "'" + c + "'"; +}; + +exports.showStringImpl = function (s) { + var l = s.length; + return "\"" + s.replace( + /[\0-\x1F\x7F"\\]/g, + function (c, i) { // jshint ignore:line + switch (c) { + case "\"": + case "\\": + return "\\" + c; + case "\a": return "\\a"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case "\v": return "\\v"; + } + var k = i + 1; + var empty = k < l && s[k] >= "0" && s[k] <= "9" ? "\\&" : ""; + return "\\" + c.charCodeAt(0).toString(10) + empty; + } + ) + "\""; +}; + +exports.showArrayImpl = function (f) { + return function (xs) { + var ss = []; + for (var i = 0, l = xs.length; i < l; i++) { + ss[i] = f(xs[i]); + } + return "[" + ss.join(",") + "]"; + }; +}; diff --git a/src/Data/Show.purs b/src/Data/Show.purs new file mode 100644 index 00000000..18ec08cf --- /dev/null +++ b/src/Data/Show.purs @@ -0,0 +1,35 @@ +module Data.Show (class Show, show) where + +-- | The `Show` type class represents those types which can be converted into +-- | a human-readable `String` representation. +-- | +-- | While not required, it is recommended that for any expression `x`, the +-- | string `show x` be executable PureScript code which evaluates to the same +-- | value as the expression `x`. +class Show a where + show :: a -> String + +instance showBoolean :: Show Boolean where + show true = "true" + show false = "false" + +instance showInt :: Show Int where + show = showIntImpl + +instance showNumber :: Show Number where + show = showNumberImpl + +instance showChar :: Show Char where + show = showCharImpl + +instance showString :: Show String where + show = showStringImpl + +instance showArray :: Show a => Show (Array a) where + show = showArrayImpl show + +foreign import showIntImpl :: Int -> String +foreign import showNumberImpl :: Number -> String +foreign import showCharImpl :: Char -> String +foreign import showStringImpl :: String -> String +foreign import showArrayImpl :: forall a. (a -> String) -> Array a -> String diff --git a/src/Data/Unit.js b/src/Data/Unit.js new file mode 100644 index 00000000..0748554a --- /dev/null +++ b/src/Data/Unit.js @@ -0,0 +1,5 @@ +"use strict"; + +// module Data.Unit + +exports.unit = {}; diff --git a/src/Data/Unit.purs b/src/Data/Unit.purs new file mode 100644 index 00000000..d69e1fbb --- /dev/null +++ b/src/Data/Unit.purs @@ -0,0 +1,17 @@ +module Data.Unit where + +import Data.Show (class Show) + +-- | The `Unit` type has a single inhabitant, called `unit`. It represents +-- | values with no computational content. +-- | +-- | `Unit` is often used, wrapped in a monadic type constructor, as the +-- | return type of a computation where only +-- | the _effects_ are important. +foreign import data Unit :: * + +-- | `unit` is the sole inhabitant of the `Unit` type. +foreign import unit :: Unit + +instance showUnit :: Show Unit where + show _ = "unit" diff --git a/src/Data/Void.purs b/src/Data/Void.purs new file mode 100644 index 00000000..4f2c3d35 --- /dev/null +++ b/src/Data/Void.purs @@ -0,0 +1,13 @@ +module Data.Void where + +import Data.Show (class Show) + +newtype Void = Void Void + +instance showVoid :: Show Void where + show _ = "Void" + +absurd :: forall a. Void -> a +absurd a = spin a + where + spin (Void b) = spin b diff --git a/src/Prelude.js b/src/Prelude.js deleted file mode 100644 index cd1049a7..00000000 --- a/src/Prelude.js +++ /dev/null @@ -1,261 +0,0 @@ -/* global exports */ -"use strict"; - -// module Prelude - -//- Functor -------------------------------------------------------------------- - -exports.arrayMap = function (f) { - return function (arr) { - var l = arr.length; - var result = new Array(l); - for (var i = 0; i < l; i++) { - result[i] = f(arr[i]); - } - return result; - }; -}; - -//- Bind ----------------------------------------------------------------------- - -exports.arrayBind = function (arr) { - return function (f) { - var result = []; - for (var i = 0, l = arr.length; i < l; i++) { - Array.prototype.push.apply(result, f(arr[i])); - } - return result; - }; -}; - -//- Monoid --------------------------------------------------------------------- - -exports.concatString = function (s1) { - return function (s2) { - return s1 + s2; - }; -}; - -exports.concatArray = function (xs) { - return function (ys) { - return xs.concat(ys); - }; -}; - -//- Semiring ------------------------------------------------------------------- - -exports.intAdd = function (x) { - return function (y) { - /* jshint bitwise: false */ - return x + y | 0; - }; -}; - -exports.intMul = function (x) { - return function (y) { - /* jshint bitwise: false */ - return x * y | 0; - }; -}; - -exports.numAdd = function (n1) { - return function (n2) { - return n1 + n2; - }; -}; - -exports.numMul = function (n1) { - return function (n2) { - return n1 * n2; - }; -}; - -//- ModuloSemiring ------------------------------------------------------------- - -exports.intDiv = function (x) { - return function (y) { - /* jshint bitwise: false */ - return x / y | 0; - }; -}; - -exports.intMod = function (x) { - return function (y) { - return x % y; - }; -}; - -exports.numDiv = function (n1) { - return function (n2) { - return n1 / n2; - }; -}; - -//- Ring ----------------------------------------------------------------------- - -exports.intSub = function (x) { - return function (y) { - /* jshint bitwise: false */ - return x - y | 0; - }; -}; - -exports.numSub = function (n1) { - return function (n2) { - return n1 - n2; - }; -}; - -//- Eq ------------------------------------------------------------------------- - -exports.refEq = function (r1) { - return function (r2) { - return r1 === r2; - }; -}; - -exports.refIneq = function (r1) { - return function (r2) { - return r1 !== r2; - }; -}; - -exports.eqArrayImpl = function (f) { - return function (xs) { - return function (ys) { - if (xs.length !== ys.length) return false; - for (var i = 0; i < xs.length; i++) { - if (!f(xs[i])(ys[i])) return false; - } - return true; - }; - }; -}; - -exports.ordArrayImpl = function (f) { - return function (xs) { - return function (ys) { - var i = 0; - var xlen = xs.length; - var ylen = ys.length; - while (i < xlen && i < ylen) { - var x = xs[i]; - var y = ys[i]; - var o = f(x)(y); - if (o !== 0) { - return o; - } - i++; - } - if (xlen === ylen) { - return 0; - } else if (xlen > ylen) { - return -1; - } else { - return 1; - } - }; - }; -}; - -//- Ord ------------------------------------------------------------------------ - -exports.unsafeCompareImpl = function (lt) { - return function (eq) { - return function (gt) { - return function (x) { - return function (y) { - return x < y ? lt : x > y ? gt : eq; - }; - }; - }; - }; -}; - -//- Bounded -------------------------------------------------------------------- - -exports.topInt = 2147483647; -exports.bottomInt = -2147483648; - -exports.topChar = String.fromCharCode(65535); -exports.bottomChar = String.fromCharCode(0); - -//- BooleanAlgebra ------------------------------------------------------------- - -exports.boolOr = function (b1) { - return function (b2) { - return b1 || b2; - }; -}; - -exports.boolAnd = function (b1) { - return function (b2) { - return b1 && b2; - }; -}; - -exports.boolNot = function (b) { - return !b; -}; - -//- Show ----------------------------------------------------------------------- - -exports.showIntImpl = function (n) { - return n.toString(); -}; - -exports.showNumberImpl = function (n) { - /* jshint bitwise: false */ - return n === (n | 0) ? n + ".0" : n.toString(); -}; - -exports.showCharImpl = function (c) { - var code = c.charCodeAt(0); - if (code < 0x20 || code === 0x7F) { - switch (c) { - case "\a": return "'\\a'"; - case "\b": return "'\\b'"; - case "\f": return "'\\f'"; - case "\n": return "'\\n'"; - case "\r": return "'\\r'"; - case "\t": return "'\\t'"; - case "\v": return "'\\v'"; - } - return "'\\" + code.toString(10) + "'"; - } - return c === "'" || c === "\\" ? "'\\" + c + "'" : "'" + c + "'"; -}; - -exports.showStringImpl = function (s) { - var l = s.length; - return "\"" + s.replace( - /[\0-\x1F\x7F"\\]/g, - function (c, i) { // jshint ignore:line - switch (c) { - case "\"": - case "\\": - return "\\" + c; - case "\a": return "\\a"; - case "\b": return "\\b"; - case "\f": return "\\f"; - case "\n": return "\\n"; - case "\r": return "\\r"; - case "\t": return "\\t"; - case "\v": return "\\v"; - } - var k = i + 1; - var empty = k < l && s[k] >= "0" && s[k] <= "9" ? "\\&" : ""; - return "\\" + c.charCodeAt(0).toString(10) + empty; - } - ) + "\""; -}; - -exports.showArrayImpl = function (f) { - return function (xs) { - var ss = []; - for (var i = 0, l = xs.length; i < l; i++) { - ss[i] = f(xs[i]); - } - return "[" + ss.join(",") + "]"; - }; -}; diff --git a/src/Prelude.purs b/src/Prelude.purs index 21ec9095..102afdc4 100644 --- a/src/Prelude.purs +++ b/src/Prelude.purs @@ -1,872 +1,52 @@ module Prelude - ( Unit(), unit - , ($), (#) - , flip - , const - , asTypeOf - , otherwise - , Semigroupoid, compose, (<<<), (>>>) - , Category, id - , Functor, map, (<$>), (<#>), void - , Apply, apply, (<*>) - , Applicative, pure, liftA1 - , Bind, bind, (>>=) - , Monad, return, liftM1, ap - , Semigroup, append, (<>), (++) - , Semiring, add, zero, mul, one, (+), (*) - , ModuloSemiring, div, mod, (/) - , Ring, sub, negate, (-) - , Num - , DivisionRing - , Eq, eq, (==), (/=) - , Ordering(..), Ord, compare, (<), (>), (<=), (>=) - , unsafeCompare - , Bounded, top, bottom - , BoundedOrd - , BooleanAlgebra, conj, disj, not, (&&), (||) - , Show, show + ( module Control.Applicative + , module Control.Apply + , module Control.Bind + , module Control.Category + , module Control.Monad + , module Control.Semigroupoid + , module Data.Boolean + , module Data.BooleanAlgebra + , module Data.Bounded + , module Data.BoundedOrd + , module Data.DivisionRing + , module Data.Eq + , module Data.Function + , module Data.Functor + , module Data.ModuloSemiring + , module Data.Num + , module Data.Ord + , module Data.Ordering + , module Data.Ring + , module Data.Semigroup + , module Data.Semiring + , module Data.Show + , module Data.Unit + , module Data.Void ) where --- | The `Unit` type has a single inhabitant, called `unit`. It represents --- | values with no computational content. --- | --- | `Unit` is often used, wrapped in a monadic type constructor, as the --- | return type of a computation where only --- | the _effects_ are important. -newtype Unit = Unit {} - --- | `unit` is the sole inhabitant of the `Unit` type. -unit :: Unit -unit = Unit {} - -infixr 0 $ -infixl 1 # - --- | Applies a function to its argument. --- | --- | ```purescript --- | length $ groupBy productCategory $ filter isInStock $ products --- | ``` --- | --- | is equivalent to: --- | --- | ```purescript --- | length (groupBy productCategory (filter isInStock products)) --- | ``` --- | --- | `($)` is different from [`(#)`](#-2) because it is right-infix instead of --- | left: `a $ b $ c $ d x = a $ (b $ (c $ (d $ x))) = a (b (c (d x)))` -($) :: forall a b. (a -> b) -> a -> b -($) f x = f x - --- | Applies an argument to a function. --- | --- | ```purescript --- | products # filter isInStock # groupBy productCategory # length --- | ``` --- | --- | is equivalent to: --- | --- | ```purescript --- | length (groupBy productCategory (filter isInStock products)) --- | ``` --- | --- | `(#)` is different from [`($)`](#-1) because it is left-infix instead of --- | right: `x # a # b # c # d = (((x # a) # b) # c) # d = d (c (b (a x)))` -(#) :: forall a b. a -> (a -> b) -> b -(#) x f = f x - --- | Flips the order of the arguments to a function of two arguments. --- | --- | ```purescript --- | flip const 1 2 = const 2 1 = 2 --- | ``` -flip :: forall a b c. (a -> b -> c) -> b -> a -> c -flip f b a = f a b - --- | Returns its first argument and ignores its second. --- | --- | ```purescript --- | const 1 "hello" = 1 --- | ``` -const :: forall a b. a -> b -> a -const a _ = a - --- | This function returns its first argument, and can be used to assert type --- | equalities. This can be useful when types are otherwise ambiguous. --- | --- | ```purescript --- | main = print $ [] `asTypeOf` [0] --- | ``` --- | --- | If instead, we had written `main = print []`, the type of the argument --- | `[]` would have been ambiguous, resulting in a compile-time error. -asTypeOf :: forall a. a -> a -> a -asTypeOf x _ = x - --- | An alias for `true`, which can be useful in guard clauses: --- | --- | ```purescript --- | max x y | x >= y = x --- | | otherwise = y --- | ``` -otherwise :: Boolean -otherwise = true - --- | A `Semigroupoid` is similar to a [`Category`](#category) but does not --- | require an identity element `id`, just composable morphisms. --- | --- | `Semigroupoid`s must satisfy the following law: --- | --- | - Associativity: `p <<< (q <<< r) = (p <<< q) <<< r` --- | --- | One example of a `Semigroupoid` is the function type constructor `(->)`, --- | with `(<<<)` defined as function composition. -class Semigroupoid a where - compose :: forall b c d. a c d -> a b c -> a b d - -instance semigroupoidFn :: Semigroupoid (->) where - compose f g x = f (g x) - -infixr 9 >>> -infixr 9 <<< - --- | `(<<<)` is an alias for `compose`. -(<<<) :: forall a b c d. (Semigroupoid a) => a c d -> a b c -> a b d -(<<<) = compose - --- | Forwards composition, or `(<<<)` with its arguments reversed. -(>>>) :: forall a b c d. (Semigroupoid a) => a b c -> a c d -> a b d -(>>>) = flip compose - --- | `Category`s consist of objects and composable morphisms between them, and --- | as such are [`Semigroupoids`](#semigroupoid), but unlike `semigroupoids` --- | must have an identity element. --- | --- | Instances must satisfy the following law in addition to the --- | `Semigroupoid` law: --- | --- | - Identity: `id <<< p = p <<< id = p` -class (Semigroupoid a) <= Category a where - id :: forall t. a t t - -instance categoryFn :: Category (->) where - id x = x - --- | A `Functor` is a type constructor which supports a mapping operation --- | `(<$>)`. --- | --- | `(<$>)` can be used to turn functions `a -> b` into functions --- | `f a -> f b` whose argument and return types use the type constructor `f` --- | to represent some computational context. --- | --- | Instances must satisfy the following laws: --- | --- | - Identity: `(<$>) id = id` --- | - Composition: `(<$>) (f <<< g) = (f <$>) <<< (g <$>)` -class Functor f where - map :: forall a b. (a -> b) -> f a -> f b - -instance functorFn :: Functor ((->) r) where - map = compose - -instance functorArray :: Functor Array where - map = arrayMap - -foreign import arrayMap :: forall a b. (a -> b) -> Array a -> Array b - -infixl 4 <$> -infixl 1 <#> - --- | `(<$>)` is an alias for `map` -(<$>) :: forall f a b. (Functor f) => (a -> b) -> f a -> f b -(<$>) = map - --- | `(<#>)` is `(<$>)` with its arguments reversed. For example: --- | --- | ```purescript --- | [1, 2, 3] <#> \n -> n * n --- | ``` -(<#>) :: forall f a b. (Functor f) => f a -> (a -> b) -> f b -(<#>) fa f = f <$> fa - --- | The `void` function is used to ignore the type wrapped by a --- | [`Functor`](#functor), replacing it with `Unit` and keeping only the type --- | information provided by the type constructor itself. --- | --- | `void` is often useful when using `do` notation to change the return type --- | of a monadic computation: --- | --- | ```purescript --- | main = forE 1 10 \n -> void do --- | print n --- | print (n * n) --- | ``` -void :: forall f a. (Functor f) => f a -> f Unit -void fa = const unit <$> fa - --- | The `Apply` class provides the `(<*>)` which is used to apply a function --- | to an argument under a type constructor. --- | --- | `Apply` can be used to lift functions of two or more arguments to work on --- | values wrapped with the type constructor `f`. It might also be understood --- | in terms of the `lift2` function: --- | --- | ```purescript --- | lift2 :: forall f a b c. (Apply f) => (a -> b -> c) -> f a -> f b -> f c --- | lift2 f a b = f <$> a <*> b --- | ``` --- | --- | `(<*>)` is recovered from `lift2` as `lift2 ($)`. That is, `(<*>)` lifts --- | the function application operator `($)` to arguments wrapped with the --- | type constructor `f`. --- | --- | Instances must satisfy the following law in addition to the `Functor` --- | laws: --- | --- | - Associative composition: `(<<<) <$> f <*> g <*> h = f <*> (g <*> h)` --- | --- | Formally, `Apply` represents a strong lax semi-monoidal endofunctor. -class (Functor f) <= Apply f where - apply :: forall a b. f (a -> b) -> f a -> f b - -instance applyFn :: Apply ((->) r) where - apply f g x = f x (g x) - -instance applyArray :: Apply Array where - apply = ap - -infixl 4 <*> - --- | `(<*>)` is an alias for `apply`. -(<*>) :: forall f a b. (Apply f) => f (a -> b) -> f a -> f b -(<*>) = apply - --- | The `Applicative` type class extends the [`Apply`](#apply) type class --- | with a `pure` function, which can be used to create values of type `f a` --- | from values of type `a`. --- | --- | Where [`Apply`](#apply) provides the ability to lift functions of two or --- | more arguments to functions whose arguments are wrapped using `f`, and --- | [`Functor`](#functor) provides the ability to lift functions of one --- | argument, `pure` can be seen as the function which lifts functions of --- | _zero_ arguments. That is, `Applicative` functors support a lifting --- | operation for any number of function arguments. --- | --- | Instances must satisfy the following laws in addition to the `Apply` --- | laws: --- | --- | - Identity: `(pure id) <*> v = v` --- | - Composition: `(pure <<<) <*> f <*> g <*> h = f <*> (g <*> h)` --- | - Homomorphism: `(pure f) <*> (pure x) = pure (f x)` --- | - Interchange: `u <*> (pure y) = (pure ($ y)) <*> u` -class (Apply f) <= Applicative f where - pure :: forall a. a -> f a - -instance applicativeFn :: Applicative ((->) r) where - pure = const - -instance applicativeArray :: Applicative Array where - pure x = [x] - --- | `return` is an alias for `pure`. -return :: forall m a. (Applicative m) => a -> m a -return = pure - --- | `liftA1` provides a default implementation of `(<$>)` for any --- | [`Applicative`](#applicative) functor, without using `(<$>)` as provided --- | by the [`Functor`](#functor)-[`Applicative`](#applicative) superclass --- | relationship. --- | --- | `liftA1` can therefore be used to write [`Functor`](#functor) instances --- | as follows: --- | --- | ```purescript --- | instance functorF :: Functor F where --- | map = liftA1 --- | ``` -liftA1 :: forall f a b. (Applicative f) => (a -> b) -> f a -> f b -liftA1 f a = pure f <*> a - --- | The `Bind` type class extends the [`Apply`](#apply) type class with a --- | "bind" operation `(>>=)` which composes computations in sequence, using --- | the return value of one computation to determine the next computation. --- | --- | The `>>=` operator can also be expressed using `do` notation, as follows: --- | --- | ```purescript --- | x >>= f = do y <- x --- | f y --- | ``` --- | --- | where the function argument of `f` is given the name `y`. --- | --- | Instances must satisfy the following law in addition to the `Apply` --- | laws: --- | --- | - Associativity: `(x >>= f) >>= g = x >>= (\k => f k >>= g)` --- | --- | Associativity tells us that we can regroup operations which use `do` --- | notation so that we can unambiguously write, for example: --- | --- | ```purescript --- | do x <- m1 --- | y <- m2 x --- | m3 x y --- | ``` -class (Apply m) <= Bind m where - bind :: forall a b. m a -> (a -> m b) -> m b - -instance bindFn :: Bind ((->) r) where - bind m f x = f (m x) x - -instance bindArray :: Bind Array where - bind = arrayBind - -foreign import arrayBind :: forall a b. Array a -> (a -> Array b) -> Array b - -infixl 1 >>= - --- | `(>>=)` is an alias for `bind`. -(>>=) :: forall m a b. (Bind m) => m a -> (a -> m b) -> m b -(>>=) = bind - --- | The `Monad` type class combines the operations of the `Bind` and --- | `Applicative` type classes. Therefore, `Monad` instances represent type --- | constructors which support sequential composition, and also lifting of --- | functions of arbitrary arity. --- | --- | Instances must satisfy the following laws in addition to the --- | `Applicative` and `Bind` laws: --- | --- | - Left Identity: `pure x >>= f = f x` --- | - Right Identity: `x >>= pure = x` -class (Applicative m, Bind m) <= Monad m - -instance monadFn :: Monad ((->) r) -instance monadArray :: Monad Array - --- | `liftM1` provides a default implementation of `(<$>)` for any --- | [`Monad`](#monad), without using `(<$>)` as provided by the --- | [`Functor`](#functor)-[`Monad`](#monad) superclass relationship. --- | --- | `liftM1` can therefore be used to write [`Functor`](#functor) instances --- | as follows: --- | --- | ```purescript --- | instance functorF :: Functor F where --- | map = liftM1 --- | ``` -liftM1 :: forall m a b. (Monad m) => (a -> b) -> m a -> m b -liftM1 f a = do - a' <- a - return (f a') - --- | `ap` provides a default implementation of `(<*>)` for any --- | [`Monad`](#monad), without using `(<*>)` as provided by the --- | [`Apply`](#apply)-[`Monad`](#monad) superclass relationship. --- | --- | `ap` can therefore be used to write [`Apply`](#apply) instances as --- | follows: --- | --- | ```purescript --- | instance applyF :: Apply F where --- | apply = ap --- | ``` -ap :: forall m a b. (Monad m) => m (a -> b) -> m a -> m b -ap f a = do - f' <- f - a' <- a - return (f' a') - --- | The `Semigroup` type class identifies an associative operation on a type. --- | --- | Instances are required to satisfy the following law: --- | --- | - Associativity: `(x <> y) <> z = x <> (y <> z)` --- | --- | One example of a `Semigroup` is `String`, with `(<>)` defined as string --- | concatenation. -class Semigroup a where - append :: a -> a -> a - -infixr 5 <> -infixr 5 ++ - --- | `(<>)` is an alias for `append`. -(<>) :: forall s. (Semigroup s) => s -> s -> s -(<>) = append - --- | `(++)` is an alternative alias for `append`. -(++) :: forall s. (Semigroup s) => s -> s -> s -(++) = append - -instance semigroupString :: Semigroup String where - append = concatString - -instance semigroupUnit :: Semigroup Unit where - append _ _ = unit - -instance semigroupFn :: (Semigroup s') => Semigroup (s -> s') where - append f g = \x -> f x <> g x - -instance semigroupOrdering :: Semigroup Ordering where - append LT _ = LT - append GT _ = GT - append EQ y = y - -instance semigroupArray :: Semigroup (Array a) where - append = concatArray - -foreign import concatString :: String -> String -> String -foreign import concatArray :: forall a. Array a -> Array a -> Array a - --- | The `Semiring` class is for types that support an addition and --- | multiplication operation. --- | --- | Instances must satisfy the following laws: --- | --- | - Commutative monoid under addition: --- | - Associativity: `(a + b) + c = a + (b + c)` --- | - Identity: `zero + a = a + zero = a` --- | - Commutative: `a + b = b + a` --- | - Monoid under multiplication: --- | - Associativity: `(a * b) * c = a * (b * c)` --- | - Identity: `one * a = a * one = a` --- | - Multiplication distributes over addition: --- | - Left distributivity: `a * (b + c) = (a * b) + (a * c)` --- | - Right distributivity: `(a + b) * c = (a * c) + (b * c)` --- | - Annihiliation: `zero * a = a * zero = zero` -class Semiring a where - add :: a -> a -> a - zero :: a - mul :: a -> a -> a - one :: a - -instance semiringInt :: Semiring Int where - add = intAdd - zero = 0 - mul = intMul - one = 1 - -instance semiringNumber :: Semiring Number where - add = numAdd - zero = 0.0 - mul = numMul - one = 1.0 - -instance semiringUnit :: Semiring Unit where - add _ _ = unit - zero = unit - mul _ _ = unit - one = unit - -infixl 6 + -infixl 7 * - --- | `(+)` is an alias for `add`. -(+) :: forall a. (Semiring a) => a -> a -> a -(+) = add - --- | `(*)` is an alias for `mul`. -(*) :: forall a. (Semiring a) => a -> a -> a -(*) = mul - -foreign import intAdd :: Int -> Int -> Int -foreign import intMul :: Int -> Int -> Int -foreign import numAdd :: Number -> Number -> Number -foreign import numMul :: Number -> Number -> Number - --- | The `Ring` class is for types that support addition, multiplication, --- | and subtraction operations. --- | --- | Instances must satisfy the following law in addition to the `Semiring` --- | laws: --- | --- | - Additive inverse: `a - a = (zero - a) + a = zero` -class (Semiring a) <= Ring a where - sub :: a -> a -> a - -instance ringInt :: Ring Int where - sub = intSub - -instance ringNumber :: Ring Number where - sub = numSub - -instance ringUnit :: Ring Unit where - sub _ _ = unit - -infixl 6 - - --- | `(-)` is an alias for `sub`. -(-) :: forall a. (Ring a) => a -> a -> a -(-) = sub - --- | `negate x` can be used as a shorthand for `zero - x`. -negate :: forall a. (Ring a) => a -> a -negate a = zero - a - -foreign import intSub :: Int -> Int -> Int -foreign import numSub :: Number -> Number -> Number - --- | The `ModuloSemiring` class is for types that support addition, --- | multiplication, division, and modulo (division remainder) operations. --- | --- | Instances must satisfy the following law in addition to the `Semiring` --- | laws: --- | --- | - Remainder: ``a / b * b + (a `mod` b) = a`` -class (Semiring a) <= ModuloSemiring a where - div :: a -> a -> a - mod :: a -> a -> a - -instance moduloSemiringInt :: ModuloSemiring Int where - div = intDiv - mod = intMod - -instance moduloSemiringNumber :: ModuloSemiring Number where - div = numDiv - mod _ _ = 0.0 - -instance moduloSemiringUnit :: ModuloSemiring Unit where - div _ _ = unit - mod _ _ = unit - -infixl 7 / - --- | `(/)` is an alias for `div`. -(/) :: forall a. (ModuloSemiring a) => a -> a -> a -(/) = div - -foreign import intDiv :: Int -> Int -> Int -foreign import numDiv :: Number -> Number -> Number -foreign import intMod :: Int -> Int -> Int - --- | A `Ring` where every nonzero element has a multiplicative inverse. --- | --- | Instances must satisfy the following law in addition to the `Ring` and --- | `ModuloSemiring` laws: --- | --- | - Multiplicative inverse: `(one / x) * x = one` --- | --- | As a consequence of this ```a `mod` b = zero``` as no divide operation --- | will have a remainder. -class (Ring a, ModuloSemiring a) <= DivisionRing a - -instance divisionRingNumber :: DivisionRing Number -instance divisionRingUnit :: DivisionRing Unit - --- | The `Num` class is for types that are commutative fields. --- | --- | Instances must satisfy the following law in addition to the --- | `DivisionRing` laws: --- | --- | - Commutative multiplication: `a * b = b * a` -class (DivisionRing a) <= Num a - -instance numNumber :: Num Number -instance numUnit :: Num Unit - --- | The `Eq` type class represents types which support decidable equality. --- | --- | `Eq` instances should satisfy the following laws: --- | --- | - Reflexivity: `x == x = true` --- | - Symmetry: `x == y = y == x` --- | - Transitivity: if `x == y` and `y == z` then `x == z` -class Eq a where - eq :: a -> a -> Boolean - -infix 4 == -infix 4 /= - --- | `(==)` is an alias for `eq`. Tests whether one value is equal to another. -(==) :: forall a. (Eq a) => a -> a -> Boolean -(==) = eq - --- | `(/=)` tests whether one value is _not equal_ to another. Shorthand for --- | `not (x == y)`. -(/=) :: forall a. (Eq a) => a -> a -> Boolean -(/=) x y = not (x == y) - -instance eqBoolean :: Eq Boolean where - eq = refEq - -instance eqInt :: Eq Int where - eq = refEq - -instance eqNumber :: Eq Number where - eq = refEq - -instance eqChar :: Eq Char where - eq = refEq - -instance eqString :: Eq String where - eq = refEq - -instance eqUnit :: Eq Unit where - eq _ _ = true - -instance eqArray :: (Eq a) => Eq (Array a) where - eq = eqArrayImpl (==) - -instance eqOrdering :: Eq Ordering where - eq LT LT = true - eq GT GT = true - eq EQ EQ = true - eq _ _ = false - -foreign import refEq :: forall a. a -> a -> Boolean -foreign import refIneq :: forall a. a -> a -> Boolean -foreign import eqArrayImpl :: forall a. (a -> a -> Boolean) -> Array a -> Array a -> Boolean - --- | The `Ordering` data type represents the three possible outcomes of --- | comparing two values: --- | --- | `LT` - The first value is _less than_ the second. --- | `GT` - The first value is _greater than_ the second. --- | `EQ` - The first value is _equal to_ the second. -data Ordering = LT | GT | EQ - --- | The `Ord` type class represents types which support comparisons with a --- | _total order_. --- | --- | `Ord` instances should satisfy the laws of total orderings: --- | --- | - Reflexivity: `a <= a` --- | - Antisymmetry: if `a <= b` and `b <= a` then `a = b` --- | - Transitivity: if `a <= b` and `b <= c` then `a <= c` -class (Eq a) <= Ord a where - compare :: a -> a -> Ordering - -instance ordBoolean :: Ord Boolean where - compare = unsafeCompare - -instance ordInt :: Ord Int where - compare = unsafeCompare - -instance ordNumber :: Ord Number where - compare = unsafeCompare - -instance ordString :: Ord String where - compare = unsafeCompare - -instance ordChar :: Ord Char where - compare = unsafeCompare - -instance ordUnit :: Ord Unit where - compare _ _ = EQ - -instance ordArray :: (Ord a) => Ord (Array a) where - compare xs ys = compare 0 $ ordArrayImpl (\x y -> case compare x y of - EQ -> 0 - LT -> 1 - GT -> -1) xs ys - -foreign import ordArrayImpl :: forall a. (a -> a -> Int) -> Array a -> Array a -> Int - -instance ordOrdering :: Ord Ordering where - compare LT LT = EQ - compare EQ EQ = EQ - compare GT GT = EQ - compare LT _ = LT - compare EQ LT = GT - compare EQ GT = LT - compare GT _ = GT - -infixl 4 < -infixl 4 > -infixl 4 <= -infixl 4 >= - --- | Test whether one value is _strictly less than_ another. -(<) :: forall a. (Ord a) => a -> a -> Boolean -(<) a1 a2 = case a1 `compare` a2 of - LT -> true - _ -> false - --- | Test whether one value is _strictly greater than_ another. -(>) :: forall a. (Ord a) => a -> a -> Boolean -(>) a1 a2 = case a1 `compare` a2 of - GT -> true - _ -> false - --- | Test whether one value is _non-strictly less than_ another. -(<=) :: forall a. (Ord a) => a -> a -> Boolean -(<=) a1 a2 = case a1 `compare` a2 of - GT -> false - _ -> true - --- | Test whether one value is _non-strictly greater than_ another. -(>=) :: forall a. (Ord a) => a -> a -> Boolean -(>=) a1 a2 = case a1 `compare` a2 of - LT -> false - _ -> true - -unsafeCompare :: forall a. a -> a -> Ordering -unsafeCompare = unsafeCompareImpl LT EQ GT - -foreign import unsafeCompareImpl :: forall a. Ordering -> Ordering -> Ordering -> a -> a -> Ordering - --- | The `Bounded` type class represents types that are finite. --- | --- | Although there are no "internal" laws for `Bounded`, every value of `a` --- | should be considered less than or equal to `top` by some means, and greater --- | than or equal to `bottom`. --- | --- | The lack of explicit `Ord` constraint allows flexibility in the use of --- | `Bounded` so it can apply to total and partially ordered sets, boolean --- | algebras, etc. -class Bounded a where - top :: a - bottom :: a - -instance boundedBoolean :: Bounded Boolean where - top = true - bottom = false - -instance boundedUnit :: Bounded Unit where - top = unit - bottom = unit - -instance boundedOrdering :: Bounded Ordering where - top = GT - bottom = LT - -instance boundedInt :: Bounded Int where - top = topInt - bottom = bottomInt - --- | Characters fall within the Unicode range. -instance boundedChar :: Bounded Char where - top = topChar - bottom = bottomChar - -instance boundedFn :: (Bounded b) => Bounded (a -> b) where - top _ = top - bottom _ = bottom - -foreign import topInt :: Int -foreign import bottomInt :: Int - -foreign import topChar :: Char -foreign import bottomChar :: Char - --- | The `BoundedOrd` type class represents totally ordered finite data types. --- | --- | Instances should satisfy the following law in addition to the `Ord` laws: --- | --- | - Ordering: `bottom <= a <= top` -class (Bounded a, Ord a) <= BoundedOrd a - -instance boundedOrdBoolean :: BoundedOrd Boolean where -instance boundedOrdUnit :: BoundedOrd Unit where -instance boundedOrdOrdering :: BoundedOrd Ordering where -instance boundedOrdInt :: BoundedOrd Int where -instance boundedOrdChar :: BoundedOrd Char where - --- | The `BooleanAlgebra` type class represents types that behave like boolean --- | values. --- | --- | Instances should satisfy the following laws in addition to the `Bounded` --- | laws: --- | --- | - Associativity: --- | - `a || (b || c) = (a || b) || c` --- | - `a && (b && c) = (a && b) && c` --- | - Commutativity: --- | - `a || b = b || a` --- | - `a && b = b && a` --- | - Distributivity: --- | - `a && (b || c) = (a && b) || (a && c)` --- | - `a || (b && c) = (a || b) && (a || c)` --- | - Identity: --- | - `a || bottom = a` --- | - `a && top = a` --- | - Idempotent: --- | - `a || a = a` --- | - `a && a = a` --- | - Absorption: --- | - `a || (a && b) = a` --- | - `a && (a || b) = a` --- | - Annhiliation: --- | - `a || top = top` --- | - Complementation: --- | - `a && not a = bottom` --- | - `a || not a = top` -class (Bounded a) <= BooleanAlgebra a where - conj :: a -> a -> a - disj :: a -> a -> a - not :: a -> a - -instance booleanAlgebraBoolean :: BooleanAlgebra Boolean where - conj = boolAnd - disj = boolOr - not = boolNot - -instance booleanAlgebraUnit :: BooleanAlgebra Unit where - conj _ _ = unit - disj _ _ = unit - not _ = unit - -instance booleanAlgebraFn :: (BooleanAlgebra b) => BooleanAlgebra (a -> b) where - conj fx fy a = fx a `conj` fy a - disj fx fy a = fx a `disj` fy a - not fx a = not (fx a) - -infixr 3 && -infixr 2 || - --- | `(&&)` is an alias for `conj`. -(&&) :: forall a. (BooleanAlgebra a) => a -> a -> a -(&&) = conj - --- | `(||)` is an alias for `disj`. -(||) :: forall a. (BooleanAlgebra a) => a -> a -> a -(||) = disj - -foreign import boolOr :: Boolean -> Boolean -> Boolean -foreign import boolAnd :: Boolean -> Boolean -> Boolean -foreign import boolNot :: Boolean -> Boolean - --- | The `Show` type class represents those types which can be converted into --- | a human-readable `String` representation. --- | --- | While not required, it is recommended that for any expression `x`, the --- | string `show x` be executable PureScript code which evaluates to the same --- | value as the expression `x`. -class Show a where - show :: a -> String - -instance showBoolean :: Show Boolean where - show true = "true" - show false = "false" - -instance showInt :: Show Int where - show = showIntImpl - -instance showNumber :: Show Number where - show = showNumberImpl - -instance showChar :: Show Char where - show = showCharImpl - -instance showString :: Show String where - show = showStringImpl - -instance showUnit :: Show Unit where - show _ = "unit" - -instance showArray :: (Show a) => Show (Array a) where - show = showArrayImpl show - -instance showOrdering :: Show Ordering where - show LT = "LT" - show GT = "GT" - show EQ = "EQ" - -foreign import showIntImpl :: Int -> String -foreign import showNumberImpl :: Number -> String -foreign import showCharImpl :: Char -> String -foreign import showStringImpl :: String -> String -foreign import showArrayImpl :: forall a. (a -> String) -> Array a -> String +import Control.Applicative (class Applicative, pure, liftA1, unless, when) +import Control.Apply (class Apply, apply, (*>), (<*), (<*>)) +import Control.Bind (class Bind, bind, ifM, join, (<=<), (=<<), (>=>), (>>=)) +import Control.Category (class Category, id) +import Control.Monad (class Monad, ap, liftM1) +import Control.Semigroupoid (class Semigroupoid, compose, (<<<), (>>>)) + +import Data.Boolean (otherwise) +import Data.BooleanAlgebra (class BooleanAlgebra, conj, disj, not, (&&), (||)) +import Data.Bounded (class Bounded, bottom, top) +import Data.BoundedOrd (class BoundedOrd) +import Data.DivisionRing (class DivisionRing) +import Data.Eq (class Eq, eq, notEq, (/=), (==)) +import Data.Function (const, flip, ($), (#)) +import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>)) +import Data.ModuloSemiring (class ModuloSemiring, div, mod, (/)) +import Data.Num (class Num) +import Data.Ord (class Ord, compare, (<), (<=), (>), (>=), comparing, min, max, clamp, between) +import Data.Ordering (Ordering(..)) +import Data.Ring (class Ring, negate, sub, (-)) +import Data.Semigroup (class Semigroup, append, (<>)) +import Data.Semiring (class Semiring, add, mul, one, zero, (*), (+)) +import Data.Show (class Show, show) +import Data.Unit (Unit, unit) +import Data.Void (Void(..), absurd)