From a6fe11ed373c5fefa5cab0ae45277ab736e6733a Mon Sep 17 00:00:00 2001 From: Harry Garrood Date: Sun, 5 Jun 2016 16:19:02 +0100 Subject: [PATCH] Update download page to use stack unpack This has two main benefits over what we have currently: It means that people end up using the same install plan that we use in the binaries; currently, encouraging people to use nightly resolvers will mean that they sometimes get new versions of libraries we depend on, resulting in a set of dependencies which we haven't run the compiler test suite with, or even used together. It also means that people aren't limited to only those versions of purescript which have made it into a nightly version. For example, when we depend on some other package which isn't yet in the nightly snapshots (for example, because not everything in the snapshot works with its newer versions yet), that version of purescript would not be installable. By contrast, this approach will work for any version of PureScript which is on Hackage. --- _site/download/index.html | 19 +++++-- _site/learn/eff/index.html | 68 +++++++++++++------------- _site/learn/ffi/index.html | 23 ++++----- _site/learn/generic/index.html | 6 +-- _site/learn/getting-started/index.html | 42 ++++++++-------- _site/learn/quickcheck/index.html | 35 ++++++------- download/index.html | 19 +++++-- 7 files changed, 117 insertions(+), 95 deletions(-) diff --git a/_site/download/index.html b/_site/download/index.html index 67607e3..2a62a64 100644 --- a/_site/download/index.html +++ b/_site/download/index.html @@ -65,15 +65,28 @@

Homebrew

Stack

-

GHC 7.10.1 or newer is required to compile from source. The easiest way is to use Stack:

+

GHC 7.10.1 or newer is required to compile from source. The easiest way is to use Stack.

+ +

Update the Hackage package index:

-stack install purescript --resolver=nightly
-
+stack update + +

Download the latest source distribution and place it into a new directory in the current directory:

+
+stack unpack purescript
+ +

Compile and install PureScript:

+
+cd purescript-x.y.z   # (replace x.y.z with whichever version you just downloaded)
+stack install

This will copy the compiler and utilities into ~/.local/bin.

If you don't have Stack installed, there are install instructions here.

+

You can also install a specific version by specifying it in the stack unpack step. For example, to install 0.8.5, use:

+
+  stack unpack purescript-0.8.5
diff --git a/_site/learn/eff/index.html b/_site/learn/eff/index.html index ea7ae61..d330834 100644 --- a/_site/learn/eff/index.html +++ b/_site/learn/eff/index.html @@ -36,7 +36,7 @@

Menu

Handling Native Effects with the Eff Monad

-
By Phil Freeman, published on July 16, 2015
+
By Phil Freeman, published on May 24, 2016

In this post, I’m going to talk about PureScript’s hybrid approach to handling side-effects.

As in Haskell, values in PureScript do not have side-effects by default, and there are a number of techniques for handling “non-native” side-effects. Such techniques include the use of things like monoids, monads, applicative functors and arrows, but I’m not going to talk about those here. I’m going to talk about how PureScript handles “native” effects, i.e. effects which are provided by the runtime system, and which cannot be emulated by pure functions.

@@ -63,15 +63,15 @@

The Eff Monad

import Control.Monad.Eff import Control.Monad.Eff.Random (random) -import Control.Monad.Eff.Console (print) +import Control.Monad.Eff.Console (logShow) printRandom = do n <- random - print n + logShow n

This example requires the purescript-console and purescript-random dependencies to be installed:

pulp init
 bower install --save purescript-console purescript-random
-

If you save this file as RandomExample.purs, you will be able to compile and run it using PSCi:

+

If you save this file as src/RandomExample.purs, you will be able to compile and run it using PSCi:

pulp psci
 
 > import RandomExample
@@ -81,19 +81,20 @@ 

The Eff Monad

This program uses do-notation to combine two types of native effects provided by the Javascript runtime: random number generation and console IO.

Extensible Records and Extensible Effects

We can inspect the type of printRandom by using the :type command

-
> :type RandomExample.main
+
> import RandomExample
+> :type main

The type of main will be printed to the console. You should see a type which looks like this:

forall e. Eff (console :: CONSOLE, random :: RANDOM | e) Unit

This type looks quite complicated, but is easily explained by analogy with PureScript’s extensible records system.

Consider a simple function which uses extensible records:

-
fullName person = person.firstName ++ " " ++ person.lastName
+
fullName person = person.firstName <> " " <> person.lastName

This function creates a full name string from an object containing firstName and lastName properties. If you find the type of this function in PSCi as before, you will see this:

-
forall t. { firstName :: String, lastName :: String | t } -> String 
+
forall t. { firstName :: String, lastName :: String | t } -> String

The readable version of this type is “fullName takes an object with firstName and lastName properties and any other properties and returns a String”.

That is, fullName does not care if you pass an object with more properties, as long as the firstName and lastName properties are present:

> fullName { firstName: "Phil", lastName: "Freeman", location: "Los Angeles" }
 Phil Freeman
-

Similarly, the type of printRandom above can be interpreted as follows: “printRandom is a side-effecting computation, which can be run in any environment which supports random number generation and console IO, and any other types of side effect, and which yields a value of type Unit”.

+

Similarly, the type of printRandom above can be interpreted as follows: “printRandom is an effectful computation, which can be run in any environment which supports random number generation and console IO, and any other types of side effect, and which yields a value of type Unit”.

This is the origin of the name “extensible effects”: we can always extend the set of side-effects, as long as we can support the set of effects that we need.

Interleaving Effects

This extensibility allows code in the Eff monad to interleave different types of effects.

@@ -101,10 +102,10 @@

Interleaving Effects

forall e1. Eff (random :: RANDOM | e1) Number

which is not the same as the type of main.

However, we can instantiate the polymorphic type variable in such a way that the types do match. If we choose e1 ~ (console :: CONSOLE | e), then the two rows are equal, up to reordering.

-

Similarly, print has a type which can be instantiated to match the type of printRandom:

-
forall a e2. (Show a) => a -> Eff (console :: CONSOLE | e2) Unit
+

Similarly, logShow has a type which can be instantiated to match the type of printRandom:

+
forall a e2. Show a => a -> Eff (console :: CONSOLE | e2) Unit

This time we have to choose e2 ~ random :: RANDOM | e.

-

The key is that we don’t have to give a type for printRandom in order to be able to find these substitutions. psc will find a most general type for printRandom given the polymorphic types of random and print.

+

The key is that we don’t have to give a type for printRandom in order to be able to find these substitutions. psc will find a most general type for printRandom given the polymorphic types of random and logShow.

Aside: The Kind of Eff

Looking at the source code, you will see the following definition for Eff:

foreign import Eff :: # ! -> * -> *
@@ -117,32 +118,34 @@

Fine-Grained Effects

main :: Eff (console :: CONSOLE, random :: RANDOM) Unit
 main = do
   n <- random
-  print n
+ logShow n

(note the lack of a type variable here), then we cannot accidentally include a subcomputation which makes use of a different type of effect. This is an advantage of Eff over Haskell’s more coarsely-grained IO monad.

Handlers and Actions

-

Rows of effects can also appear on the left-hand side of a function arrow. This is what differentiates actions like print and random from effect handlers.

+

Rows of effects can also appear on the left-hand side of a function arrow. This is what differentiates actions like logShow and random from effect handlers.

While actions add to the set of required effects, a handler subtracts effects from the set.

Consider catchException from the purescript-exceptions package:

-
catchException :: forall a e. (Error -> Eff e a) -> 
-                              Eff (err :: EXCEPTION | e) a -> 
-                              Eff e a
+
catchException
+  :: forall a e
+   . (Error -> Eff e a)
+  -> Eff (err :: EXCEPTION | e) a
+  -> Eff e a

Note that the type of the effect on the right of the final function arrow requires fewer effects than the effect to its left. Namely, catchException removes the EXCEPTION effect from the set of required effects.

This is useful, because the type system can be used to delimit portions of code which require a particular effect, and then to wrap that code in a handler, embedding it inside a piece of code which does not use that effect.

For example, we can write a piece of code which uses exceptions, then wrap that code using catchException to embed the computation in a piece of code which does not use exceptions.

purescript-eff also defines the handler runPure, which takes a computation with no side-effects, and safely evaluates it as a pure value:

-
type Pure a = forall e. Eff e a
+
type Pure a = Eff () a
 
 runPure :: forall a. Pure a -> a

For example, we can define a version of the division function for which division by zero results in an exception:

module ErrorsExample where
 
 import Prelude
-import Control.Monad.Eff
-import Control.Monad.Eff.Exception
+import Control.Monad.Eff (Eff)
+import Control.Monad.Eff.Exception (EXCEPTION, throw)
 
 divide :: forall e. Int -> Int -> Eff (err :: EXCEPTION | e) Int
 divide _ 0 = throw "Division by zero"
-divide n m = return (n / m)
+divide n m = pure (n / m)

If we have already defined this function, we can use the runPure and catchException handlers to define a version of divide which reports its errors using Either:

import Data.Either
 
@@ -169,32 +172,32 @@ 

Defining New Effect Types

return f; };

The Eff Monad is Magic

-

The psc compiler has special support for the Eff monad. Ordinarily, a chain of monadic binds might result in poor performance when executed in nodejs or in the browser. However, the compiler can generate code for the Eff monad without explicit calls to the monadic bind function >>=.

+

The psc compiler has special support for the Eff monad. Ordinarily, a chain of monadic binds might result in poor performance when executed in Node or in the browser. However, the compiler can generate code for the Eff monad without explicit calls to the monadic bind function >>=.

Take the random number generation from the start of the post. If we compile this example without optimizations, we end up the following Javascript:

-
var main = 
+
var main =
   Prelude[">>="]
     (Control_Monad_Eff.monadEff())
 	(Control_Monad_Eff_Random.random)
 	(function (n) {
-      return Control_Monad_Eff_Console.print(Prelude.showNumber())(n);
+      return Control_Monad_Eff_Console.logShow(Prelude.showNumber())(n);
     });

However, if we use the default optimizations, the calls to Eff’s monadic bind function are inlined, resulting the following tidier Javascript:

var main = function __do() {
   var n = Control_Monad_Eff_Random.random();
-  return Control_Monad_Eff_Console.print(Prelude.showNumber())(n)();
+  return Control_Monad_Eff_Console.logShow(Prelude.showNumber())(n)();
 };

While this is a small improvement, the benefit is greater when using multiple nested calls to >>=.

The improvement is even more marked when optimizations are used in conjunction with tail call elimination. Consider the following recursive program which prints an increasing sequence of numbers to the console:

go n = do
-  print n
+  logShow n
   go (n + 1)
 
 main = go 1

Without optimizations, the compiler generates the following Javascript, which fails after a few iterations with a stack overflow:

-
var go = 
+
var go =
   Prelude[">>="]
     (Control_Monad_Eff.monadEff())
-	(Control_Monad_Eff_Console.print(Prelude.showNumber())(n))
+	(Control_Monad_Eff_Console.logShow(Prelude.showNumber())(n))
 	(function (_) {
       return go(n + 1);
     });
@@ -203,7 +206,7 @@

The Eff Monad is Magic

return function __do() { var n = __copy_n; tco: while (true) { - Control_Monad_Eff_Console.print(Prelude.showNumber())(n)(); + Control_Monad_Eff_Console.logShow(Prelude.showNumber())(n)(); var __tco_n = n + 1; n = __tco_n; continue tco; @@ -217,11 +220,11 @@

Efficient Mutation with ST

collatz n = pureST do r <- newSTRef n count <- newSTRef 0 - untilE $ do - modifySTRef count $ (+) 1 + untilE do + modifySTRef count (_ + 1) m <- readSTRef r writeSTRef r $ if m `mod` 2 == 0 then m / 2 else 3 * m + 1 - return $ m == 1 + pure (m == 1) readSTRef count

In this case, psc notices that the mutable variables r and count are scoped by runST and so can safely be turned into local mutable variables.

The resulting Javascript is surprisingly short:

@@ -235,8 +238,7 @@

Efficient Mutation with ST

var m = r; r = (m % 2 === 0) ? m / 2 : 3 * m + 1; return m === 1; - })()) { - }; + })()) { }; return {}; })(); return count; diff --git a/_site/learn/ffi/index.html b/_site/learn/ffi/index.html index 4d74a43..ff7e58a 100644 --- a/_site/learn/ffi/index.html +++ b/_site/learn/ffi/index.html @@ -46,6 +46,8 @@

Calling PureScript from JavascriptLet’s take the following simple module as an example:

module Test where
 
+import Prelude
+
 gcd :: Int -> Int -> Int
 gcd n m | n == 0 = m
 gcd n m | m == 0 = n
@@ -69,28 +71,22 @@ 

Understanding Name Generation

example' = 100

generates the following Javascript:

var example$prime = 100;
-

This scheme also applies to names of infix operators:

-
(%) a b = ...
-

generates

-
var $percent = function(a) { ... }

Calling Javascript from PureScript

Javascript values and functions can be used from PureScript by using the FFI. The problem becomes how to choose suitable types for values originating in Javascript.

The general rule regarding types is that you can enforce as little or as much type safety as you like when using the FFI, but you should be careful to avoid common pitfalls when dealing with Javascript values, like the possibility of null or undefined values being returned from a Javascript function. Functions defined in the Prelude and core libraries tend to err on the side of type safety where possible.

Foreign Modules

In PureScript, JavaScript code is wrapped using a foreign module. A foreign module is just a CommonJS module which is associated with a PureScript module. Foreign modules are required to adhere to certain conventions:

    -
  • The module must contain a comment of the form // module ModuleName, which associates the foreign module with its companion PureScript module.
  • +
  • The name of the foreign module must be the same as its companion PureScript module, with its extension changed to .js. This associates the foreign module with the PureScript module.
  • All exports must be of the form exports.name = value;, specified at the top level.

Here is an example, where we export a function which computes interest amounts from a foreign module:

"use strict";
 
-// module Interest
-
 exports.calculateInterest = function(amount) {
   return amount * 0.1;
 };
-

This file should be saved as src/Interest.js. The corresponding PureScript module Interest will be saved in src/Interest.purs (these filenames are merely conventions, but are used by certain tools, such as the Pulp build tool), and will look like this:

+

This file should be saved as src/Interest.js. The corresponding PureScript module Interest will be saved in src/Interest.purs, and will look like this:

module Interest where
 
 foreign import calculateInterest :: Number -> Number
@@ -100,14 +96,14 @@

Functions of Multiple Arguments

Suppose we wanted to modify our calculateInterest function to take a second argument:

"use strict";
 
-// module Interest
-
 exports.calculateInterest = function(amount, months) {
   return amount * Math.exp(0.1, months);
 };

A correct foreign import declaration now should use a foreign type whose runtime representation correctly handles functions of multiple arguments. The purescript-functions package provides a collection of such types for function arities from 0 to 10:

module Interest where
 
+import Data.Function (Fn2)
+
 foreign import calculateInterest :: Fn2 Number Number Number

Here, the Fn2 type constructor is used to wrap Javascript functions of two arguments. We can write a curried wrapper function in PureScript which will allow partial application:

calculateInterestCurried :: Number -> Number -> Number
@@ -115,8 +111,6 @@ 

Functions of Multiple Arguments

An alternative is to use curried functions in the native module, using multiple nested functions, each with a single argument, as the runtime representation of the function type constructor (->) dictates:

"use strict";
 
-// module Interest
-
 exports.calculateInterest = function(amount) {
   return function(months) {
     return amount * Math.exp(0.1, months);
@@ -129,9 +123,10 @@ 

Handling Constrained Types

For example, let’s write a simple PureScript function with a constrained type, and look at the generated Javascript.

module Test where
 
-import Data.Tuple
+import Prelude
+import Data.Tuple (Tuple(..))
 
-inOrder :: forall a. (Ord a) => a -> a -> Tuple a a
+inOrder :: forall a. Ord a => a -> a -> Tuple a a
 inOrder a1 a2 | a1 < a2 = Tuple a1 a2
 inOrder a1 a2 = Tuple a2 a1

The generated Javascript looks like this:

diff --git a/_site/learn/generic/index.html b/_site/learn/generic/index.html index 7d29399..4b98fc0 100644 --- a/_site/learn/generic/index.html +++ b/_site/learn/generic/index.html @@ -43,8 +43,8 @@

Generics Overview

PureScript’s generics are supported by the purescript-generics library, and in particular, the Data.Generic.Generic type class:

class Generic a where
   toSignature :: Proxy a -> GenericSignature
-  toSpine :: a -> GenericSpine
-  fromSpine :: GenericSpine -> Maybe a
+ toSpine :: a -> GenericSpine + fromSpine :: GenericSpine -> Maybe a

Generic defines three functions:

  • toSignature creates a generic signature for a type. We can think of this as a representation of a type at runtime.
  • @@ -85,7 +85,7 @@

    Handling Foreign Data

    return $ Person { name, location }

This is not too bad, but real-world records often contain many more fields. Let’s see how to verify the same data using Generic.

The purescript-foreign-generic library defines a function readGeneric, with the following type:

-
readGeneric :: forall a. (Generic a) => Options -> Foreign -> F a
+
readGeneric :: forall a. Generic a => Options -> Foreign -> F a

The Options type here is based on the options record from Haskell’s aeson library. For our purposes, the default options will work, but we need to turn on the unwrapNewtypes option, so that our newtype constructor gets ignored during serialization:

myOptions :: Options
 myOptions = defaultOptions { unwrapNewtypes = true }
diff --git a/_site/learn/getting-started/index.html b/_site/learn/getting-started/index.html index cf45efa..c35c29f 100644 --- a/_site/learn/getting-started/index.html +++ b/_site/learn/getting-started/index.html @@ -36,7 +36,7 @@

Menu

Getting Started with PureScript

-
By Phil Freeman, published on December 13, 2015
+
By Phil Freeman, published on May 24, 2016

Welcome to the PureScript community blog! In this first post, I’m going to walk through the basics of getting set up to use the PureScript compiler psc, and its interactive mode psci.

I’ll start with the installation of the compiler and Pulp build tool, and then go through the basic usage of psci, working towards a solution of problem 1 from Project Euler.

@@ -73,14 +73,8 @@

Installing Dependencies

Working in PSCI

PSCi is the interactive mode of PureScript. It is useful for working with pure computations, and for testing ideas.

Open PSCi by typing pulp psci at the command line. Pulp will create a file in your directory called .psci, which contains instructions to PSCi to load your modules and dependencies. If you invoke the PSCi executable directly, you would need to load these files by hand.

-
 ____                 ____            _       _   
-|  _ \ _   _ _ __ ___/ ___|  ___ _ __(_)_ __ | |_ 
-| |_) | | | | '__/ _ \___ \ / __| '__| | '_ \| __|
-|  __/| |_| | | |  __/___) | (__| |  | | |_) | |_ 
-|_|    \__,_|_|  \___|____/ \___|_|  |_| .__/ \__|
-                                       |_|        
-
-:? shows help
+
PSCi, version 0.9.0
+Type :? for help
 >

As the introduction indicates, you can type :? to see a list of commands:

The following commands are available:
@@ -89,8 +83,6 @@ 

Working in PSCI

:quit Quit PSCi :reset Discard all imported modules and declared bindings :browse <module> See all functions in <module> -:load <file> Load <file> for importing -:foreign <file> Load foreign module <file> :type <expr> Show the type of <expr> :kind <type> Show the kind of <type> :show import Show all imported modules @@ -100,12 +92,15 @@

Working in PSCI

--> https://github.com/purescript/purescript/wiki/psci

We will use a selection of these commands during this tutorial.

Start by pressing the Tab key to use the autocompletion feature. You will see a collection of names of functions from the Prelude which are available to use.

-

To see the type of one of these values, use the :type command, followed by a space, followed by the name of the value:

-
> :type Prelude.map
+

To see the type of one of these values, first import the appropriate module using the import command. Then, use the :type command, followed by a space, followed by the name of the value:

+
> import Prelude
+> :type map
 forall a b f. (Prelude.Functor f) => (a -> b) -> f a -> f b
-> :type Data.List.zip
+
+> import Data.List
+> :type zip
 forall a b. Data.List.List a -> Data.List.List b -> Data.List.List (Data.Tuple.Tuple a b)
-

We will be using some of the functions from the Prelude and Data.List modules, so import those by using the import keyword:

+

We will be using some of the functions from the Prelude and Data.List modules, so make sure you have imported those by using the import keyword:

import Prelude
 import Data.List

Note that using Tab to autocomplete names can be a useful time-saving device in psci.

@@ -138,7 +133,7 @@

Solving Project Euler #1

Compiling a Solution

Now that we’ve seen how to use psci to reach the answer, let’s move our solution into a source file and compile it.

Create a new text file src/Euler.purs and copy the following code:

-
module Euler1 where
+
module Euler where
 
 import Prelude
 
@@ -152,7 +147,8 @@ 

Compiling a Solution

answer = sum multiples

It is possible to load this file directly into PSCi and to continue working:

pulp psci
-> Euler1.answer
+> import Euler
+> answer
 233168
 > :quit
 See ya!
@@ -166,7 +162,8 @@

Writing a Test Suite

module Test.Main where
 
 import Prelude
-import Euler1 (answer)
+
+import Euler (answer)
 import Test.Assert (assert)
 
 main = do
@@ -178,14 +175,15 @@ 

Creating Executables

module Main where
 
 import Prelude
-import Euler1
-import Control.Monad.Eff.Console
+
+import Euler (answer)
+import Control.Monad.Eff.Console (log)
 
 main = do
-  log ("The answer is " ++ show answer)
+ log ("The answer is " <> show answer)

The pulp run command can be used to compile and run the Main module:

> pulp run
-* Building project in /Users/paf31/Documents/Code/purescript/pulp-test
+* Building project in pulp-test
 * Build successful.
 The answer is 233168

Conclusion

diff --git a/_site/learn/quickcheck/index.html b/_site/learn/quickcheck/index.html index 5fd5ee1..09d4550 100644 --- a/_site/learn/quickcheck/index.html +++ b/_site/learn/quickcheck/index.html @@ -59,21 +59,21 @@

Testing PureScript Functions

This indicates 100 successful random test runs.

Error Messages

Let’s see what happens when we try testing a broken property:

-
> quickCheck \n -> n + 1 == n 
+
> quickCheck \n -> n + 1 == n

You should see an exception printed to the console:

Error: Test 1 failed:
 Failed: Test returned false

That’s not a very helpful error, so let’s improve it:

-
> quickCheck \n -> n + 1 == n <?> "Test failed for input " ++ show n
+
> quickCheck \n -> n + 1 == n <?> "Test failed for input " <> show n

This time you should see the following failure message:

-
Error: Test 1 failed: 
+
Error: Test 1 failed:
 Test failed for input -654791

Alternatively, we could use the === operator, which provides a better error message:

-
> quickCheck \n -> n + 1 === n 
-Error: Test 1 failed: 
+
> quickCheck \n -> n + 1 === n
+Error: Test 1 failed:
 -663820 /= -663821

Example 1 - GCD Function

-

Let’s write an implementation of the greatest common divisor function in PSCi (you will need to enable multiline mode):

+

Let’s write an implementation of the greatest common divisor function in PSCi (you will need to enable multiline mode by restarting PSCi with --multi-line-mode):

> let
     gcd 0 n = n
     gcd n 0 = n
@@ -83,7 +83,7 @@ 

Example 1 - GCD Function

gcd n m = gcd n (m - n)

Now let’s assert some basic properties that we expect to hold of the gcd function.

> quickCheck \n -> gcd n 1 === 1
-

This test should pass, but will take a while, because the standard random generator for integers which comes bundled with purescript-quickcheck generates integers in the range -1000000 to 1000000.

+

This test should pass, but might take a while, because the standard random generator for integers which comes bundled with purescript-quickcheck generates integers in the range -1000000 to 1000000.

We can modify our test to only consider small integers:

> quickCheck \n -> gcd (n / 1000) 1 === 1

This time, the test should complete quickly. However, we’ve coupled the generation of our data (/ 1000) with the property we’re testing, which is against the spirit of QuickCheck. A better approach is to define a newtype which can be used to generate small integers.

@@ -91,6 +91,7 @@

Example 1 - GCD Function

module SmallInt where
 
 import Prelude
+
 import Test.QuickCheck
 import Test.QuickCheck.Arbitrary
 
@@ -100,7 +101,7 @@ 

Example 1 - GCD Function

runInt (SmallInt i) = i instance arbSmallInt :: Arbitrary SmallInt where - arbitrary = (/ 1000) <$> arbitrary
+ arbitrary = map (_ / 1000) arbitrary

Back in PSCi, we can now test properties without having to explicitly define how to generate our random data:

> quickCheck \(SmallInt n) (SmallInt m) -> gcd n m == gcd m n

The idea is that the particular scheme that is chosen to generate data should be indicated by the types of our function arguments, so newtypes can be quite useful when defining multiple data generation schemes for a single type.

@@ -111,8 +112,8 @@

Example 2 - Testing Higher O

The first functor law says that if you map a function which does not modify its argument (the identity function) over a structure, then the structure should not be modified either.

> import Data.Array
 
-> let 
-    firstFunctorLaw :: [Int] -> Boolean
+> let
+    firstFunctorLaw :: Array Int -> Boolean
     firstFunctorLaw arr = map id arr == arr
 
 > quickCheck firstFunctorLaw
@@ -121,9 +122,9 @@ 

Example 2 - Testing Higher O unit

The second functor law says that mapping two functions over a structure one-by-one is equivalent to mapping their composition over the structure:

> let
-    secondFunctorLaw :: (Int -> Int) -> (Int -> Int) -> [Int] -> Boolean
+    secondFunctorLaw :: (Int -> Int) -> (Int -> Int) -> Array Int -> Boolean
     secondFunctorLaw f g arr = map f (map g arr) == map (f <<< g) arr
-  
+
 > quickCheck secondFunctorLaw
 
 100/100 test(s) passed.
@@ -134,19 +135,19 @@ 

Testing Javascript Functions

Copy the contents of that file into src/UnderscoreFFI.purs, and reload PSCi with that module loaded:

> import UnderscoreFFI

The UnderscoreFFI module defines a wrapper for the sortBy function. Let’s test that the function is idempotent:

-
> let 
-    sortIsIdempotent :: [Int] -> Boolean
+
> let
+    sortIsIdempotent :: Array Int -> Boolean
     sortIsIdempotent arr = sortBy id (sortBy id arr) == sortBy id arr
-  
+
 > quickCheck sortIsIdempotent
 
 100/100 test(s) passed.
 unit

In fact, we don’t need to sort by the identity function. Since QuickCheck supports higher-order functions, we can test with a randomly-generated sorting function:

-
> let 
+
> let
     sortIsIdempotent' :: (Int -> Int) -> [Int] -> Boolean
     sortIsIdempotent' f arr = sortBy f (sortBy f arr) == sortBy f arr
-  
+
 > quickCheck sortIsIdempotent
 
 100/100 test(s) passed.
diff --git a/download/index.html b/download/index.html
index 65c7bc5..a0cf4c9 100644
--- a/download/index.html
+++ b/download/index.html
@@ -29,15 +29,28 @@ 

Homebrew

Stack

-

GHC 7.10.1 or newer is required to compile from source. The easiest way is to use Stack:

+

GHC 7.10.1 or newer is required to compile from source. The easiest way is to use Stack.

+ +

Update the Hackage package index:

-stack install purescript --resolver=nightly
-
+stack update
+ +

Download the latest source distribution and place it into a new directory in the current directory:

+
+stack unpack purescript
+ +

Compile and install PureScript:

+
+cd purescript-x.y.z   # (replace x.y.z with whichever version you just downloaded)
+stack install

This will copy the compiler and utilities into ~/.local/bin.

If you don't have Stack installed, there are install instructions here.

+

You can also install a specific version by specifying it in the stack unpack step. For example, to install 0.8.5, use:

+
+  stack unpack purescript-0.8.5