Skip to content

Updates for 0.12 #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ language: node_js
dist: trusty
sudo: required
node_js: stable
env:
- PATH=$HOME/purescript:$PATH
install:
- TAG=$(wget -q -O - https://github.com/purescript/purescript/releases/latest --server-response --max-redirect 0 2>&1 | sed -n -e 's/.*Location:.*tag\///p')
- 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:
- bower install --production
- npm run -s build
- bower install
- npm -s test
- npm run -s test
after_success:
- >-
test $TRAVIS_TAG &&
Expand Down
80 changes: 35 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Build Status](https://travis-ci.org/purescript-contrib/purescript-argonaut-core.svg?branch=master)](https://travis-ci.org/purescript-contrib/purescript-argonaut-core)
[![Maintainer: slamdata](https://img.shields.io/badge/maintainer-slamdata-lightgrey.svg)](http://github.com/slamdata)

Core part of `purescript-argonaut` that contains basic types for `Json`, folds over them, tests, printer and parser.
Core part of `purescript-argonaut` that contains basic types for `Json`, case analysis, printer and parser.

## Installation

Expand All @@ -31,7 +31,7 @@ data Json
| JNumber Number
| JBoolean Boolean
| JArray (Array Json)
| JObject (StrMap Json)
| JObject (Object Json)
```

And indeed, some might even say this is the obvious approach.
Expand All @@ -45,25 +45,6 @@ both in terms of speed and memory churn.

Much of the design of Argonaut follows naturally from this design decision.

### Types

The most important type in this library is, of course, `Json`, which is the
type of JSON data in its native JavaScript representation.

As the (hypothetical) algebraic data type declaration above indicates, there
are six possibilities for a JSON value: it can be `null`, a string, a number, a
boolean, an array of JSON values, or an object mapping string keys to JSON
values.

For convenience, and to ensure that values have the appropriate underlying
data representations, Argonaut also declares types for each of these individual
possibilities, whose names correspond to the data constructor names above.

Therefore, `JString`, `JNumber`, and `JBoolean` are synonyms for the primitive
PureScript types `String`, `Number`, and `Boolean` respectively; `JArray` is a
synonym for `Array Json`; and `JObject` is a synonym for `StrMap Json`.
Argonaut defines a type `JNull` as the type of the `null` value in JavaScript.

### Introducing Json values

(Or, where do `Json` values come from?)
Expand Down Expand Up @@ -97,7 +78,7 @@ follows:

```purescript
import Data.Tuple (Tuple(..))
import Data.StrMap as StrMap
import Foreign.Object as StrMap
import Data.Argonaut.Core as A

someNumber = A.fromNumber 23.6
Expand All @@ -113,32 +94,41 @@ someObject = A.fromObject (StrMap.fromFoldable [

### Eliminating/matching on `Json` values

We can perform case analysis for `Json` values using the `foldJson` function.
We can perform case analysis for `Json` values using the `caseJson` function.
This function is necessary because `Json` is not an algebraic data type. If
`Json` were an algebraic data type, we would not have as much need for this
function, because we could perform pattern matching with a `case ... of`
expression instead.

The type of `foldJson` is:
The type of `caseJson` is:

```purescript
foldJson :: forall a.
(JNull -> a) -> (JBoolean -> a) -> (JNumber -> a) ->
(JString -> a) -> (JArray -> a) -> (JObject -> a) ->
Json -> a
caseJson
:: forall a
. (Unit -> a)
-> (Boolean -> a)
-> (Number -> a)
-> (String -> a)
-> (Array Json -> a)
-> (Object Json -> a)
-> Json
-> a
```

That is, `foldJson` takes six functions, which all must return values of some
particular type `a`, together with one `Json` value. `foldJson` itself also
That is, `caseJson` takes six functions, which all must return values of some
particular type `a`, together with one `Json` value. `caseJson` itself also
returns a value of the same type `a`.

A use of `foldJson` is very similar to a `case ... of` expression, as it allows
you to handle each of the six possibilities for the `Json` value you passed in.
Thinking of it this way, each of the six function arguments is like one of the
case alternatives. Just like in a `case ... of` expression, the final value
A use of `caseJson` is very similar to a `case ... of` expression, as it allows
you to handle each of the six possibilities for the `Json` value you passed in. Thinking of it this way, each of the six function arguments is like one of the
case alternatives.

The function that takes `Unit` as an argument is for matching `null` values. As there is only one possible `null` value, we use the PureScript `Unit` type, as correspondingly there is only one possible `Unit` value.

Just like in a `case ... of` expression, the final value
that the whole expression evaluates to comes from evaluating exactly one of the
'alternatives' (functions) that you pass in. In fact, you can tell that this
is the case just by looking at the type signature of `foldJson`, because of a
is the case just by looking at the type signature of `caseJson`, because of a
property called *parametricity* (although a deeper explanation of parametricity
is outside the scope of this tutorial).

Expand All @@ -151,15 +141,15 @@ exports.anotherArray = [0.0, {foo: 'bar'}, false];
exports.anotherObject = {foo: 1, bar: [2,2]};
```

Then we can match on them in PureScript using `foldJson`:
Then we can match on them in PureScript using `caseJson`:

```purescript
foreign import anotherNumber :: Json
foreign import anotherArray :: Json
foreign import anotherObject :: Json

basicInfo :: Json -> String
basicInfo = foldJson
basicInfo = caseJson
(const "It was null")
(\b -> "Got a boolean: " <>
if b then "it was true!" else "It was false.")
Expand All @@ -168,7 +158,7 @@ basicInfo = foldJson
" characters long.")
(\xs -> "Got an array, which had " <> Data.Array.length xs <>
" items.")
(\obj -> "Got an object, which had " <> Data.StrMap.size obj <>
(\obj -> "Got an object, which had " <> Foreign.Object.size obj <>
" items.")
```

Expand All @@ -178,20 +168,20 @@ basicInfo anotherArray -- => "Got an array, which had 3 items."
basicInfo anotherObject -- => "Got an object, which had 2 items."
```

`foldJson` is the fundamental function for pattern matching on `Json` values;
any kind of pattern matching you might want to do can be done with `foldJson`.
`caseJson` is the fundamental function for pattern matching on `Json` values;
any kind of pattern matching you might want to do can be done with `caseJson`.

However, `foldJson` is not always comfortable to use, so Argonaut provides a
few other simpler versions for convenience. For example, the `foldJsonX`
However, `caseJson` is not always comfortable to use, so Argonaut provides a
few other simpler versions for convenience. For example, the `caseJsonX`
functions can be used to match on a specific type. The first argument acts as a
default value, to be used if the `Json` value turned out not to be that type.
For example, we can write a function which tests whether a JSON value is the
string "lol" like this:

```purescript
foldJsonString :: forall a. a -> (JString -> a) -> Json -> a
caseJsonString :: forall a. a -> (String -> a) -> Json -> a

isJsonLol = foldJsonString false (_ == "lol")
isJsonLol = caseJsonString false (_ == "lol")
```

If the `Json` value is not a string, the default `false` is used. Otherwise,
Expand All @@ -203,7 +193,7 @@ type, you'll get a `Just` value. Otherwise, you'll get `Nothing`. For example,
we could have written `isJsonLol` like this, too:

```purescript
toString :: Json -> Maybe JString
toString :: Json -> Maybe String

isJsonLol json =
case toString json of
Expand Down
17 changes: 12 additions & 5 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,19 @@
"package.json"
],
"dependencies": {
"purescript-enums": "^3.0.0",
"purescript-functions": "^3.0.0",
"purescript-gen": "^1.0.0",
"purescript-maps": "^3.0.0"
"purescript-arrays": "^5.0.0",
"purescript-control": "^4.0.0",
"purescript-either": "^4.0.0",
"purescript-foreign-object": "^1.0.0",
"purescript-functions": "^4.0.0",
"purescript-gen": "^2.0.0",
"purescript-maybe": "^4.0.0",
"purescript-nonempty": "^5.0.0",
"purescript-prelude": "^4.0.0",
"purescript-strings": "^4.0.0",
"purescript-tailrec": "^4.0.0"
},
"devDependencies": {
"purescript-quickcheck": "^4.6.1"
"purescript-quickcheck": "^5.0.0"
}
}
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
"test": "pulp test"
},
"devDependencies": {
"eslint": "^3.19.0",
"pulp": "^11.0.0",
"purescript-psa": "^0.5.0",
"purescript": "^0.11.1",
"rimraf": "^2.6.1"
"eslint": "^4.19.1",
"pulp": "^12.2.0",
"purescript-psa": "^0.6.0",
"rimraf": "^2.6.2"
}
}
8 changes: 2 additions & 6 deletions src/Data/Argonaut/Core.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ function id(x) {
return x;
}

exports.fromNull = function () {
return null;
};

exports.fromBoolean = id;
exports.fromNumber = id;
exports.fromString = id;
Expand All @@ -27,8 +23,8 @@ function isArray(a) {
return objToString.call(a) === "[object Array]";
}

exports._foldJson = function (isNull, isBool, isNum, isStr, isArr, isObj, j) {
if (j == null) return isNull(null);
exports._caseJson = function (isNull, isBool, isNum, isStr, isArr, isObj, j) {
if (j == null) return isNull();
else if (typeof j === "boolean") return isBool(j);
else if (typeof j === "number") return isNum(j);
else if (typeof j === "string") return isStr(j);
Expand Down
Loading