Skip to content
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

upgrade to new bs-platofrm 4.0.7 #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
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
89 changes: 57 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This has been heavily inspired by the [Rust Cookbook](https://brson.github.io/ru
* [Js.Dict](#jsdict)
* [Associative list](#associative-list)
* [Hashtbl](#hashtbl)
* [Belt.HashMap.String](#belthashmapstring)
+ [Use a Set in a recursive type](#use-a-set-in-a-recursive-type)
* [Promises](#promises)
+ [Creating new Promises](#creating-new-promises)
Expand Down Expand Up @@ -182,8 +183,8 @@ let () =
Use [Random module](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Random.html) to generate random numbers

```ml
let () =
Js.log (Random.int 5)
let () = Random.init (int_of_float (Js.Date.now ()))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if this line was explained, since it isn't very obvious what the purpose of all these functions are

let () = (Random.int 5) |> Js.log
Copy link
Owner

@glennsl glennsl Nov 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parentheses here are superfluous when using the pipe operator

```

#### Log a message to the console
Expand Down Expand Up @@ -240,29 +241,30 @@ let () =
Js.log "no matches"
```

Or using [bs-revamp](https://github.com/glennsl/bs-revamp) with the same input:

```ml
input |> Revamp.matches("<p\\b[^>]*>(.*?)<\\/p>", ~flags=[Revamp.IgnoreCase])
|> Rebase.Seq.forEach(Js.log);
```

#### Dasherize camelCased identifiers inside string literals using Regular Expression

Uses [bs-revamp](https://github.com/glennsl/bs-revamp)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather see a PR update bs-revamp than have the example removed. I don't think much would need to be changed.

The addition of an example that does not use bs-revamp is great though.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. bs-revamp just needs some love.


```ml
let code = {|
let borderLeftColor = "borderLeftColor";
let borderRightColor = "borderRightColor";
|}

let matchLetter letter _ _ = "-" ^ (Js.String.toLowerCase letter)

let matchLiterals _ p1 _ _ =
let t =
Js.String.unsafeReplaceBy0
[%re "/[A-Z]/g"] matchLetter p1 in
{j|"$t"|j}

let () =
code |> Revamp.replace {|"([^"]*)"|} (* Matches the content of string literals *)
(Revamp.replace "[A-Z]" (fun letter -> (* Matches uppercase letters *)
"-" ^ letter |> Js.String.toLowerCase)) (* Convert to lower case and prefix with a dash *)
|> Js.log

(code |>
Js.String.unsafeReplaceBy1
[%re
"/\"([^\"]*)\"/g"]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This formatting is a bit weird. I don't think the line break is particularly necessary here.

matchLiterals)
|> Js.log

(* Outputs:
let borderLeftColor = "border-left-color";
let borderRightColor = "border-right-color";
Expand Down Expand Up @@ -349,7 +351,7 @@ let () =

###### Hashtbl

Mutable, string key type, cross-platform
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this removed? Do you not think it's a significant property to mention?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry. It's werid in my machine yesterday. Hashtbl didn't work.

Mutable, string key type

```ml
let painIndexMap = Hashtbl.create 10
Expand All @@ -370,6 +372,29 @@ let () =
painIndexMap |> Hashtbl.iter (fun k v -> Js.log {j|key:$k, val:$v|j})
```

###### Belt.HashMap.String

Mutable, string key type, BuckleScript only

```ml
open Belt
let painIndexMap = HashMap.String.make ~hintSize:10
let () =
let open HashMap.String in
set painIndexMap "western paper wasp" 1.0;
set painIndexMap "yellowjacket" 2.0;
set painIndexMap "honey bee" 2.0;
set painIndexMap "red paper wasp" 3.0;
set painIndexMap "tarantula hawk" 4.0;
set painIndexMap "bullet ant" 4.0

let () =
HashMap.String.set painIndexMap "bumble bee" 2.0

let () =
painIndexMap |. HashMap.String.forEach (fun k -> fun v -> Js.log {j|key:$k, val:$v|j})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Belt.HashMap example is great, but perhaps it should show the generalized HashMap since it's more widely applicable?

I'm also not a fan of using the fast pipe since it's mostly just confusing. Could you rewrite it without that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok. but why do you think fast pipe is confusing?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In javascript world, many apis are often attached to objects, and often chainable. data is the first argument in function.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's already a well established pipe operator, not just in OCaml/Reason but in many other languages as well. The fast pipe isn't even language-specific but platform-specific. It won't work outside BuckleScript, which makes it unusable with anything written to target anything other than BuckleScript. But even within BuckleScript it's both confusing and painful to have to remember which convention and pipe operator you have to use with a given function, especially if you have to juggle both in the same "chain" of function calls. And for newcomers, which is the intended audience here, unfamiliarity makes this confusion much worse.

Of course it's really the bad design of Belt itself that's the root problem here and the fast pipe is mostly a workaround to make serious use more convenient, but we can't do much about that other than to not show it, which I don't think is very honest since it's still a real alternative. But we can at least avoid using cryptic operators that's highly likely to be unfamiliar and confusing to newcomers when it's largely unnecessary to demonstrate it.

```

#### Use a Set in a recursive type

The task is to make something like this using Set:
Expand Down Expand Up @@ -432,7 +457,7 @@ let timer =
accidentally partially apply the function *)
let _ : Js.Global.timeoutId =
Js.Global.setTimeout
(fun () -> (resolve "Done!")[@bs])
(fun () -> (resolve "Done!")[@bs])
1000
in ()
)
Expand All @@ -452,7 +477,7 @@ let _ : unit Js.Promise.t =
(* Chaining *)
let _ : unit Js.Promise.t =
Js.Promise.then_
(fun value -> Js.Promise.resolve (Js.log value))
(fun value -> Js.Promise.resolve (Js.log value))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't your doing, but I just noticed how weird it is to resolve the return value of Js.log. And being more explicit with Js.log value; Js.Promise.resolve () isn't much more verbose either. What do you think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both ok. Js.Promise.resolve (Js.log value) is less code. I think everyone knows the return value from Js.log is unit.

(Js.Promise.then_
(fun value -> Js.Promise.resolve (value + 1))
(Js.Promise.resolve 1))
Expand All @@ -474,7 +499,7 @@ let _ : unit Js.Promise.t =
let open Js.Promise in
all2 (resolve 1, resolve "a")
|> then_ (fun (v1, v2) ->
Js.log ("Value 1: " ^ string_of_int v1);
Js.log ("Value 1: " ^ string_of_int v1);
Js.log ("Value 2: " ^ v2);
resolve ())

Expand Down Expand Up @@ -514,20 +539,20 @@ let _ : unit Js.Promise.t =
* In general, we should not rely on rejecting/catching errors for control flow;
* it's much better to use a `result` type instead.
*)
let betterOk : (string, _) Js.Result.t Js.Promise.t =
let betterOk : (string, _) Belt.Result.t Js.Promise.t =
Js.Promise.make (fun ~resolve ~reject:_ ->
resolve (Js.Result.Ok ("everything's fine")) [@bs])
resolve (Belt.Result.Ok ("everything's fine")) [@bs])

let betterOhNo : (_, string) Js.Result.t Js.Promise.t =
let betterOhNo : (_, string) Belt.Result.t Js.Promise.t =
Js.Promise.make (fun ~resolve ~reject:_ ->
resolve (Js.Result.Error ("nope nope nope")) [@bs])
resolve (Belt.Result.Error ("nope nope nope")) [@bs])

let handleResult =
Js.Promise.then_ (fun result ->
Js.Promise.resolve (
match result with
| Js.Result.Ok text -> Js.log ("OK: " ^ text)
| Js.Result.Error reason -> Js.log ("Oh no: " ^ reason)))
| Belt.Result.Ok text -> Js.log ("OK: " ^ text)
| Belt.Result.Error reason -> Js.log ("Oh no: " ^ reason)))

let _ : unit Js.Promise.t =
handleResult betterOk
Expand Down Expand Up @@ -559,6 +584,8 @@ let person = [%obj {
};
age = 32
}]

let _ = Js.log (## (## person name) first)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't valid OCaml. Looks like you wrote it in Reason and converted it in the Try Reason playground which doesn't handle ## properly. It should be let _ = Js.log (person##name##first).

I'm not sure this line should be there at all though, since the example should illustrate object creation. not object access, and could be confusing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. It should be removed.

HAHA. You are a wise man. I am an newbie. I use refmt --parse ml --print re --interface false to convert Ocaml syntaxt to Reasonml. I have to lookup Ocaml docs when I meet problems.

In fact, I am very confused. why create a new syntax , named Reasonml? Just for marketing?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly to make it more familiar and approachable to developers already familiar with JavaScript or other Algol-style languages, I think, which is a pretty sizable share of all developers.

But it also fixes a many inconsistencies and general weirdness with OCaml. I prefer Reason, even if it does have its issues too.

```

#### Raise a javascript exception, then catch it and print its message
Expand Down Expand Up @@ -713,8 +740,8 @@ external withAsyncCallback : ((Js.Json.t -> unit) -> unit) -> unit = "" [@@bs.va
let withAsyncCallback: (doneFn -> unit) -> unit =
fun f -> withAsyncCallback
(fun done_ ->
f (function | Some value -> value |> Js.Json.string |> done_
| None -> Js.false_ |> Js.Json.boolean |> done_))
f (function | Some value -> value |> Js.Json.string |> done_
| None -> false |> Js.Json.boolean |> done_))
```


Expand Down Expand Up @@ -774,7 +801,6 @@ let () =
## Node-specific

#### Read lines from a text file
Uses [bs-node](https://github.com/reasonml-community/bs-node)
```ml
let () =
Node.Fs.readFileAsUtf8Sync "README.md"
Expand All @@ -783,7 +809,7 @@ let () =
```

#### Read and parse a JSON file
Uses [bs-json](https://github.com/reasonml-community/bs-json) and [bs-node](https://github.com/reasonml-community/bs-node)
Uses [bs-json](https://github.com/reasonml-community/bs-json)
```ml
let decodeName text =
Js.Json.parseExn text
Expand All @@ -804,11 +830,10 @@ let () =
```

#### Run an external command
Uses [bs-node](https://github.com/reasonml-community/bs-node)
```ml
let () =
(* prints node's version *)
Node.(ChildProcess.execSync "node -v" (Options.options ~encoding:"utf8" ()))
Node.(Child_process.execSync "node -v" (Child_process.option ~encoding:"utf8" ()))
|> Js.log
```

Expand Down