Reading user input


#1

Here’s a tiny program:

 print_string("Now is the time for all good men to come to the aid of the party\n");
 print_newline();
 let s = read_line();
 print_string("You typed: " ++ s);
 print_newline();

Running it produces this (before I get the chance to type anything as input):

jfh$ Node src/Demo.bs.js
Now is the time for all good men to come to the aid of the party

/Users/jfh/.nvm/versions/node/v12.9.0/lib/node_modules/bs-platform/lib/js/caml_external_polyfill.js:16
    throw new Error(s + " not polyfilled by BuckleScript yet\n")
    ^

Error: caml_ml_input_scan_line not polyfilled by BuckleScript yet

    at Object.resolve (/Users/jfh/.nvm/versions/node/v12.9.0/lib/node_modules/bs-platform/lib/js/caml_external_polyfill.js:16:11)
    at scan (/Users/jfh/.nvm/versions/node/v12.9.0/lib/node_modules/bs-platform/lib/js/pervasives.js:335:38)
    at input_line (/Users/jfh/.nvm/versions/node/v12.9.0/lib/node_modules/bs-platform/lib/js/pervasives.js:367:37)
    at Object.read_line (/Users/jfh/.nvm/versions/node/v12.9.0/lib/node_modules/bs-platform/lib/js/pervasives.js:431:10)
    at Object.<anonymous> (/Users/jfh/foo/repl/src/Demo.bs.js:10:20)
    at Module._compile (internal/modules/cjs/loader.js:936:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
    at Module.load (internal/modules/cjs/loader.js:790:32)
    at Function.Module._load (internal/modules/cjs/loader.js:703:12)
    at Function.Module.runMain (internal/modules/cjs/loader.js:999:10)

Because read_line is actually in “Pervasives”, I figured it would probably work. Have I done something wrong? Suggestions for alternative ways to read user input?


#2

Short version: since you’re compiling and running the code on NodeJS, you’ll need to write a binding to and use the readline module: https://nodejs.org/api/readline.html

Longer version: the BuckleScript compiler does not ship with a working version of Pervasives.read_line, as you can see from the message ‘not polyfilled by BuckleScript yet’. To get equivalent functionality, you typically bind to a function which is shipped on the platform you’re running on. On NodeJS, that’s readline. In a web browser, it would be an input form or something like that.

To write BuckleScript bindings, please see the BuckleScript website documentation.


#3

There are actually several existing bindings for this already. See https://redex.github.io/keyword/cli


#4

Thanks to both of you; I’ll see how that works out!


#5

OK. I’ve tried a bunch of things without success, so I’m back. I have the feeling that some documentation might be a little out of date, and I know my understanding is limited at best.

Trying to start afresh, I’ve created a new project, so (reading down from my home directory, things look like

jfh
  reason-tests
    chat-test
       README.me
       bsconfig.json
       lib
       node_modules
       package.json
       src
          Demo.js
          Demo.bs.js

where that last file is there because I ran npm run build, and then (from the chat-test directory) tried 'node src/Demo.bs.js`, which produced the expected one-line output you get from the sample-starter code.

For making something like read_line work, I need to install a “binding” in the form of some module, but there seem to be two choices: bs-readline, and bs-node-readline. As you can see from my description above, I’m using bucklescript to compile ReasonML code to Javascript, and then running it with “node”. I’m unsure which of these I should be using, and the package descriptions don’t seem to disambiguate for me. So:

Question 1: is there a “correct” choice, in my context, for bs-readline, vs bs-node-readilne? All I really need is to be able to read some user-typed text from a terminal.

In my previous attempts, I installed both, figuring that one or the other might be “found” by either bucklescript or Node (I’m not even sure which one needs to find it!). I installed using npm i --save bs-readline, for example, because that’s what the doc at https://redex.github.io/package/bs-readline said to do. But wondering if I’d done it wrong because errors persisted — the demo program shown there wouldn’t run! — I tried to read up on the install command, and learned that the --save option is now deprecated, and the the editing of my bsconfig.json file is now done automatically (if I’m reading this correctly). Thus

Question 2: To install one of these modules, should I in fact simply type npm i bs-readline and not have to edit my bsconfig.json file?

Question 3: In what directory should I be when I run the npm i ... (or whatever) command to install these modules? In “reason-tests”? In “chat-test”? In “chat-test/node_modules”?

Any suggestions gratefully received.


#6

I figured it out, after more experimentation.

Q1: I don’t know if there’s a correct choice, but using bs-readline worked for me
Q2: typing npm i bs-readline worked fine. It created a package-lock.json file, which it said I should commit, but I’m not using a version control system yet, and just ignored that message, and things seem fine so far (for my very limited use-goals).
Q3: To make this work, I typed that command in the chat-test directory.

Notes: To test out the module, I used the sample code given there:

Readline.readline((in) => {
  Js.log(in);
  Readline.close();
});

which would not compile, because the “Readline” module could not be found. I had to edit the chat-test/src/bsconfig,json file to have a middle section that looked like this:

"suffix": ".bs.js",
"bs-dependencies": [
    "bs-readline"
],
"warnings": {
"error" : "+101"

where the "bs-readline" was the thing I added.
Even then, it wouldn’t run, because “in” is apparently a reserved word. I edited to make my sample program look like this instead:

Js.log("Hello, BuckleScript and Reason!");

Readline.readline((inp) => {
    Js.log(inp);
    Readline.close();
});

and that worked better. To actually make it run, in the chat-test directory, I typed

% npm run build
% node src/Demo.bs.js

The first of these compiles the Demo.re into javascripts, in a file called Demo.bs.js, which it places in the “source” directory even though it’s actually the output of some process. The second line runs this Javascript program. The actual execution looked like this

chat-test jfh% node src/Demo.bs.js
Hello, BuckleScript and Reason!
foobar
foobar

where the first foobar was what I typed, and the second was ReasonML’s echo of it.