1# ๐ท purescript-lazy-joe ๐ฆฅ
3Zero boilerplate ffi for purescript.
5For these days when you got the blues and are just too lazy to write ffi code.
8* [Installation](#installation)
9* [Quickstart](#quickstart)
11 * [Method chaining](#method-chaining)
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)
30 { red } <- fromDefault "chalk" -- import a module
31 log $ red "Red velvet ๐" -- use a function
36Imagine we want to use the amazing [`chalk`](https://github.com/chalk/chalk) js library for terminal styling in our purescript code.
38We start by installing chalk.
43`chalk` defines a number of functions and combinators that allow you to write coloured text to your terminal. For instance the function `red` from `chalk` prints a red string. In js you would use it like this:
46import chalk from 'chalk';
48console.log(chalk.red("Red velvet ๐"));
51Let's see how we can ffi this in our purescript code:
56 { red } <- fromDefault "chalk"
57 log $ red "Red velvet ๐"
62
65You can easily import the `default` export from a module using `fromDefault`. This will type red as `String -> String`.
69In js method chaining is a common pattern. In purescript we can use function application to model this pattern.
74In chalk, you can combine different styles by chaining them:
77import chalk from 'chalk';
79console.log(chalk.underline.bold.green('Leaf ๐'));
82In purescript, we can use function application to model this method chaining:
86 { underline } <- fromDefault "chalk"
87 log $ underline # \{ bold } -> bold # \{ green } -> green "Leaf ๐"
92.
94### Uncurried functions
96js 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:
99result = curried myFunc arg1 arg2 arg3
104E.g. we can use the `blue` function as a three-argument uncurried function:
107console.log(chalk.blue('blue', 'azul', 'blau'));
110In purescript functions are curried, so we need to curry them using `curried`:
115 { blue } <- fromDefault "chalk"
117 log $ curried blue "blue" "azul" "blau"
120Running it will print:
122
126js 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:
130 example1 = variadic func arg1
131 example1 = variadic func arg1 arg2 arg3
132 example1 = variadic func [arg1, arg2, arg3, arg4]
137In 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:
139console.log(chalk.blue('Hello', 'world!', 'Hola', 'mundo!'));
142If we need this variadic behaviour, we can use `variadic` to model this:
146 { blue } <- fromDefault "chalk"
148 log $ variadic blue "Hello"
149 log $ variadic blue "Hello" "world!"
150 log $ variadic blue [ "Hello", "world!", "Hola", "mundo!"]
155Sometimes 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:
158result <- scoped myModuleOrFunc func arg1 arg2
163Simply 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:
168 m@{ rgb } <- fromDefault "chalk"
170 log $ scoped m (curried rgb) 129 37 218 # \{ bold } -> bold "PURPLE!!! ๐ช"
173Running it will print:
175
177### Effectful functions
179js 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:
183 result :: Effect SomeResult
184 result = effectful func arg1 arg2
189Let's try another example and install minimalistic http-client `got`:
195With `got` we can create a simple http request using the `post` function and passing a url and a json body:
197import got from 'got';
199const {data} = await got.post('https://httpbin.org/anything', {
208Clearly, `post` is an effectful function, as it triggers a promise. So in purescript `post` will have the signature `Effect (Promise json)` which we can then be converted to an `Aff` using the `toAffE`.
213 { post } <- fromDefault "got"
214 resp <- Promise.toAffE $ effectful (curried post) "https://httpbin.org/anything" { json: { hello: "๐" } } >>= \{ json } -> json
218We 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.
222Use `new` to create new objects:
225myModule <- fromDefault "my-module"
226let myObj = new myModule arg1 arg2
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:
233const fuse = new Fuse(list, options);
235Then you can search on this object:
237const pattern = "my-search-pattern"
241We 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:
244fuse <- fromDefault "fuse.js"
247 [ { "title": "Old Man's War", "author": { "firstName": "John", "lastName": "Scalzi" } }
248 , { "title": "The Lock Artist", "author": { "firstName": "Steve", "lastName": "Hamilton" } }
251 { keys: [ "title", "author.firstName" ]
253 result :: Array { item :: { title :: String, author :: { firstName :: String, lastName :: String } } } <-
254 (new fuse list options) # \f@{ search } -> effectful (scoped f search) "eve"
261Kudos to @paluh for writing the [`purescript-js-object`](https://github.com/paluh/purescript-js-object) library (check it out!), which basically inspired me to write this library. @paluh's library is probably the (type-)safer option, but I thought if I am already too lazy to write ffi, then I really want to be lazy and not write anything at all. So this library follows a different implementation approach to basically not require any ffi code, at the expense of more type-safety.
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list