git.iko.soy/rowtype-yoga/purescript-lazy-joe
on main help sign in
7 files changed+173−143
since splitsnapshots
unifiedsplit
CHANGELOG.md+13 README.md+109−18 bower.json+24 packages.dhall−99 src/Lazy/Joe.purs+24−24 test.dhall+1 test/Main.purs+2−2
CHANGELOG.mdnew file+13
@@ -0,0 +1,13 @@
1+# Changelog
2+
3+
4+## v1.0.0
5+
6+Initial release. Supports:
7+
8+- importing module (defaults)
9+- currying functions
10+- scoping functions to a module or object
11+- effectful functions
12+- variadic functions (varargs)
13+- `new` constructor
README.md+109−18
@@ -1,17 +1,19 @@
11# 🎷 purescript-lazy-joe 🦥
22
3−A purescript library for these days when you got the blues and are just too lazy to write ffi code.
3+Zero boilerplate ffi for purescript.
44
5−`lazy-joe` let's you ffi your js library without having to write the typical purescript ffi boilerplate.
5+For these days when you got the blues and are just too lazy to write ffi code.
66
77## ToC
88* [Installation](#installation)
9+* [Quickstart](#quickstart)
910* [Usage](#usage)
1011 * [Method chaining](#method-chaining)
11− * [Uncurried](#uncurried)
12− * [Varargs](#varargs)
13− * [Scoped](#scoped)
14− * [Effectful](#effectful)
12+ * [Uncurried functions](#uncurried-functions)
13+ * [Vararg functions](#vararg-functions)
14+ * [Scoped functions](#scoped-functions)
15+ * [Effectful functions](#effectful-functions)
16+ * [`new` constructor](#new-constructor)
1517* [Credits](#credits)
1618
1719## Installation
@@ -20,6 +22,15 @@ A purescript library for these days when you got the blues and are just too lazy
2022spago install lazy-joe
2123```
2224
25+## Quickstart
26+
27+```
28+main :: Effect Unit
29+main = launchAff_ do
30+ { red } <- fromDefault "chalk" -- import a module
31+ log $ red "Red velvet 🎂" -- use a function
32+```
33+
2334## Usage
2435
2536Imagine we want to use the amazing [`chalk`](https://github.com/chalk/chalk) js library for terminal styling in our purescript code.
@@ -55,7 +66,12 @@ You can easily import the `default` export from a module using `fromDefault`. Th
5566
5667### Method chaining
5768
58−In js method chaining is often used. In chalk, you can combine different styles by chaining:
69+In js method chaining is a common pattern. In purescript we can use function application to model this pattern.
70+
71+
72+#### Example
73+
74+In chalk, you can combine different styles by chaining them:
5975
6076```js
6177import chalk from 'chalk';
@@ -75,31 +91,50 @@ Running it will print:
7591
7692![green leaf printed in bold green underline](./assets/green-leaf.png).
7793
78−### Uncurried
94+### Uncurried functions
95+
96+js typically uses uncurried functions (e.g. `f(a,b,c) `) instead of curried functions (e.g. `f(a)(b)(c)` ) like purescript. Use `curried` to use the uncurried js function as a curried purescript function:
97+
98+```
99+result = curried myFunc arg1 arg2 arg3
100+```
101+
102+#### Example
79103
80−js typically uses uncurried functions (e.g. `f(a,b,c) `) instead of uncurried functions (e.g. `f(a)(b)(c)` ) like purescript. E.g. we can use the `blue` function as a three-argument uncurried function:
104+E.g. we can use the `blue` function as a three-argument uncurried function:
81105
82106```js
83107console.log(chalk.blue('blue', 'azul', 'blau'));
84108```
85109
86−In purescript functions are curried, so we need to uncurry them using `uncurried`:
110+In purescript functions are curried, so we need to curry them using `curried`:
87111
88112```purescript
89113main :: Effect Unit
90114main = launchAff_ do
91115 { blue } <- fromDefault "chalk"
92116
93− log $ uncurried blue "blue" "azul" "blau"
117+ log $ curried blue "blue" "azul" "blau"
94118```
95119
96120Running it will print:
97121
98122![blue azul blau in blue colours](./assets/blau-azul.png)
99123
100−### Varargs
124+### Vararg functions
101125
102−js functions are sometimes designed to be variadic, i.e. to have a variable number of arguments. In fact, the colour methods in `chalk` are variadic methods (as you have seen in the previous example) and you can pass an arbitrary number of arguments:
126+js functions are sometimes designed to be variadic, i.e. to have a variable number of arguments. Use `variadic myModuleOrFunc func` for functions that accept varargs:
127+
128+```purescript
129+let
130+ example1 = variadic func arg1
131+ example1 = variadic func arg1 arg2 arg3
132+ example1 = variadic func [arg1, arg2, arg3, arg4]
133+```
134+
135+#### Eample
136+
137+In fact, the colour methods in `chalk` are variadic methods (as you have seen in the previous example) and you can pass an arbitrary number of arguments:
103138```js
104139console.log(chalk.blue('Hello', 'world!', 'Hola', 'mundo!'));
105140```
@@ -115,23 +150,41 @@ main = launchAff_ do
115150 log $ variadic blue [ "Hello", "world!", "Hola", "mundo!"]
116151```
117152
118−### Scoped
153+### Scoped functions
119154
120−Sometimes js functions don't work in purescript, because they sometimes use `this` internally which fails to resolve in a curried contex. E.g. simply using the `rgb` function from `chalk` as we did before will fail. To make it work again we will need to set the scope for `this` properly. You can use `scoped` to set the scope of a function to the module:
155+Sometimes js functions don't work in purescript, because they internally use `this` which fails to resolve in a curried contex. Use `scoped myModuleOrFunc func` you to make a function scoped:
156+
157+```purescript
158+result <- scoped myModuleOrFunc func arg1 arg2
159+```
160+
161+#### Example
162+
163+Simply using the `rgb` function from `chalk` as we did before will fail because it uses `this` internally. To make it work again we will need to set the scope for the function to the module:
121164
122165```purescript
123166main :: Effect Unit
124167main = launchAff_ do
125168 m@{ rgb } <- fromDefault "chalk"
126169
127− log $ scoped m (uncurried rgb) 129 37 218 # \{ bold } -> bold "PURPLE!!! 🪁"
170+ log $ scoped m (curried rgb) 129 37 218 # \{ bold } -> bold "PURPLE!!! 🪁"
128171```
129172
130173Running it will print:
131174
132175![purple in bold purple with a kite](./assets/purple-kite.png)
133176
134−### Effectful
177+### Effectful functions
178+
179+js functions very often cause side-effects (e.g. like printing to the console). Use `effectful` you to catch these side-effects and return `Effect` instead:
180+
181+```purescript
182+let
183+ result :: Effect SomeResult
184+ result = effectful func arg1 arg2
185+```
186+
187+#### Example
135188
136189Let's try another example and install minimalistic http-client `got`:
137190
@@ -158,12 +211,50 @@ Clearly, `post` is an effectful function, as it triggers a promise. So in puresc
158211main :: Effect Unit
159212main = launchAff_ do
160213 { post } <- fromDefault "got"
161− resp <- Promise.toAffE $ effectful (uncurried post) "https://httpbin.org/anything" { json: { hello: "🌎" } } >>= \{ json } -> json
214+ resp <- Promise.toAffE $ effectful (curried post) "https://httpbin.org/anything" { json: { hello: "🌎" } } >>= \{ json } -> json
162215 log resp.json
163216```
164217
165218We import the `post` from `got`. The first thing we need to do is uncurry it, since it receives two arguments, the url and the json record. We then wrap it using `effectful` so that is run in an `Effect`. We can then call the effectful js function `json()` on the resulting `Promise` to get the body, so we can just `bind` (`>>=`) it.
166219
220+### `new` constructor
221+
222+Use `new` to create new objects:
223+
224+```purescript
225+myModule <- fromDefault "my-module"
226+let myObj = new myModule arg1 arg2
227+```
228+
229+#### Example
230+
231+`fuse.js` is a library for fuzzy search. In js you use it by first creating a new `Fuse` object using `new` and passing the data as a list and some options:
232+```js
233+const fuse = new Fuse(list, options);
234+```
235+Then you can search on this object:
236+```js
237+const pattern = "my-search-pattern"
238+fuse.search(pattern)
239+```
240+
241+We first import the default export from `fuse.js` which gives us the class, which we can then pass to `new` to create the `Fuse` object:
242+
243+```purescript
244+fuse <- fromDefault "fuse.js"
245+ let
246+ list =
247+ [ { "title": "Old Man's War", "author": { "firstName": "John", "lastName": "Scalzi" } }
248+ , { "title": "The Lock Artist", "author": { "firstName": "Steve", "lastName": "Hamilton" } }
249+ ]
250+ options =
251+ { keys: [ "title", "author.firstName" ]
252+ }
253+ result :: Array { item :: { title :: String, author :: { firstName :: String, lastName :: String } } } <-
254+ (new fuse list options) # \f@{ search } -> effectful (scoped f search) "eve"
255+
256+ logShow result
257+```
167258
168259## Credits
169260
bower.jsonnew file+24
@@ -0,0 +1,24 @@
1+{
2+ "name": "purescript-lazy-joe",
3+ "license": [
4+ "MIT-0"
5+ ],
6+ "repository": {
7+ "type": "git",
8+ "url": "https://github.com/sigma-andex/purescript-lazy-joe.git"
9+ },
10+ "ignore": [
11+ "**/.*",
12+ "node_modules",
13+ "bower_components",
14+ "output"
15+ ],
16+ "dependencies": {
17+ "purescript-aff": "^v7.0.0",
18+ "purescript-aff-promise": "^v4.0.0",
19+ "purescript-effect": "^v4.0.0",
20+ "purescript-functions": "^v6.0.0",
21+ "purescript-prelude": "^v6.0.0",
22+ "purescript-unsafe-coerce": "^v6.0.0"
23+ }
24+}
packages.dhall−99
@@ -1,103 +1,4 @@
1−{-
2−Welcome to your new Dhall package-set!
31
4−Below are instructions for how to edit this file for most use
5−cases, so that you don't need to know Dhall to use it.
6−
7−## Use Cases
8−
9−Most will want to do one or both of these options:
10−1. Override/Patch a package's dependency
11−2. Add a package not already in the default package set
12−
13−This file will continue to work whether you use one or both options.
14−Instructions for each option are explained below.
15−
16−### Overriding/Patching a package
17−
18−Purpose:
19−- Change a package's dependency to a newer/older release than the
20− default package set's release
21−- Use your own modified version of some dependency that may
22− include new API, changed API, removed API by
23− using your custom git repo of the library rather than
24− the package set's repo
25−
26−Syntax:
27−where `entityName` is one of the following:
28−- dependencies
29−- repo
30−- version
31−-------------------------------
32−let upstream = --
33−in upstream
34− with packageName.entityName = "new value"
35−-------------------------------
36−
37−Example:
38−-------------------------------
39−let upstream = --
40−in upstream
41− with halogen.version = "master"
42− with halogen.repo = "https://example.com/path/to/git/repo.git"
43−
44− with halogen-vdom.version = "v4.0.0"
45− with halogen-vdom.dependencies = [ "extra-dependency" ] # halogen-vdom.dependencies
46−-------------------------------
47−
48−### Additions
49−
50−Purpose:
51−- Add packages that aren't already included in the default package set
52−
53−Syntax:
54−where `<version>` is:
55−- a tag (i.e. "v4.0.0")
56−- a branch (i.e. "master")
57−- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977")
58−-------------------------------
59−let upstream = --
60−in upstream
61− with new-package-name =
62− { dependencies =
63− [ "dependency1"
64− , "dependency2"
65− ]
66− , repo =
67− "https://example.com/path/to/git/repo.git"
68− , version =
69− "<version>"
70− }
71−-------------------------------
72−
73−Example:
74−-------------------------------
75−let upstream = --
76−in upstream
77− with benchotron =
78− { dependencies =
79− [ "arrays"
80− , "exists"
81− , "profunctor"
82− , "strings"
83− , "quickcheck"
84− , "lcg"
85− , "transformers"
86− , "foldable-traversable"
87− , "exceptions"
88− , "node-fs"
89− , "node-buffer"
90− , "node-readline"
91− , "datetime"
92− , "now"
93− ]
94− , repo =
95− "https://github.com/hdgarrood/purescript-benchotron.git"
96− , version =
97− "v7.0.0"
98− }
99−-------------------------------
100−-}
1012let upstream =
1023 https://github.com/purescript/package-sets/releases/download/psc-0.15.2-20220613/packages.dhall
1034 sha256:99f976d547980055179de2245e428f00212e36acd55d74144eab8ad8bf8570d8
src/Lazy/Joe.purs+24−24
@@ -6,8 +6,8 @@ module Lazy.Joe
66 , new
77 , class Scoped
88 , scoped
9− , class Uncurried
10− , uncurried
9+ , class Curried
10+ , curried
1111 , class Variadic
1212 , variadic
1313 , from
@@ -36,38 +36,38 @@ foreign import fromDefaultImpl :: forall mod. String -> Effect (Promise mod)
3636fromDefault :: forall mod m. MonadAff m => String -> m mod
3737fromDefault = fromDefaultImpl >>> Promise.toAffE >>> liftAff
3838
39−class Uncurried f output | output -> f where
40− uncurried :: f -> output
39+class Curried f output | output -> f where
40+ curried :: f -> output
4141
42−instance Uncurried (Fn5 a b c d e f) (a -> b -> c -> d -> e -> f) where
43− uncurried = runFn5
42+instance Curried (Fn5 a b c d e f) (a -> b -> c -> d -> e -> f) where
43+ curried = runFn5
4444
45−else instance Uncurried (Fn5 a b c d e f) (Fn5 a b c d e f) where
46− uncurried = identity
45+else instance Curried (Fn5 a b c d e f) (Fn5 a b c d e f) where
46+ curried = identity
4747
48−else instance Uncurried (Fn4 a b c d e) (a -> b -> c -> d -> e) where
49− uncurried = runFn4
48+else instance Curried (Fn4 a b c d e) (a -> b -> c -> d -> e) where
49+ curried = runFn4
5050
51−else instance Uncurried (Fn4 a b c d e) (Fn4 a b c d e) where
52− uncurried = identity
51+else instance Curried (Fn4 a b c d e) (Fn4 a b c d e) where
52+ curried = identity
5353
54−else instance Uncurried (Fn3 a b c d) (a -> b -> c -> d) where
55− uncurried = runFn3
54+else instance Curried (Fn3 a b c d) (a -> b -> c -> d) where
55+ curried = runFn3
5656
57−else instance Uncurried (Fn3 a b c d) (Fn3 a b c d) where
58− uncurried = identity
57+else instance Curried (Fn3 a b c d) (Fn3 a b c d) where
58+ curried = identity
5959
60−else instance Uncurried (Fn2 a b c) (a -> b -> c) where
61− uncurried = runFn2
60+else instance Curried (Fn2 a b c) (a -> b -> c) where
61+ curried = runFn2
6262
63−else instance Uncurried (Fn2 a b c) (Fn2 a b c) where
64− uncurried = identity
63+else instance Curried (Fn2 a b c) (Fn2 a b c) where
64+ curried = identity
6565
66−else instance Uncurried (Fn1 a b) (Fn1 a b) where
67− uncurried = identity
66+else instance Curried (Fn1 a b) (Fn1 a b) where
67+ curried = identity
6868
69−else instance Uncurried (Fn1 a b) (a -> b) where
70− uncurried = runFn1
69+else instance Curried (Fn1 a b) (a -> b) where
70+ curried = runFn1
7171
7272
7373foreign import new0 :: forall a. Fn0 a -> a
test.dhall+1
@@ -5,5 +5,6 @@ in conf // {
55 dependencies = conf.dependencies # [
66 , "spec"
77 , "debug"
8+ , "console"
89 ]
910}
test/Main.purs+2−2
@@ -6,7 +6,7 @@ import Control.Promise as Promise
66import Effect (Effect)
77import Effect.Aff (Aff, launchAff_)
88import Effect.Class.Console (log, logShow)
9−import Lazy.Joe (effectful, fromDefault, new, scoped, uncurried, variadic)
9+import Lazy.Joe (effectful, fromDefault, new, scoped, curried, variadic)
1010
1111main :: Effect Unit
1212main = launchAff_ do
@@ -39,7 +39,7 @@ main = launchAff_ do
3939 c >>= log
4040
4141 { post } <- fromDefault "got"
42− resp <- Promise.toAffE $ effectful (uncurried post) "https://httpbin.org/anything" { json: { hello: "🌎" } } >>= \{ json } -> json
42+ resp <- Promise.toAffE $ effectful (curried post) "https://httpbin.org/anything" { json: { hello: "🌎" } } >>= \{ json } -> json
4343 log resp.json
4444
4545 fuse <- fromDefault "fuse.js"