Read command-line arguments in SML - sml

I am trying to read the name of my input file that is argv[1] . This is what I’ve done so far :
val args = CommandLine.arguments() ;
val (x::y) = args ;
val _ = agora x
but I keep getting this error message :
uncaught exception Bind [nonexhaustive binding failure] .
Can anyone help ? Thank you in advance !

This is the compiler warning you that you can't be sure that the bind pattern always holds.
For example, given the following program:
val args = CommandLine.arguments ()
val (x::y) = args
val _ = print (x ^ "\n")
Compiling and running this gives:
$ mosmlc args.sml
$ ./a.out Hello
Hello
$ ./a.out
Uncaught exception:
Bind
To safely handle a variable amount of command-line arguments, you might use a case-of:
fun main () =
case CommandLine.arguments () of
[] => print ("Too few arguments!\n")
| [arg1] => print ("That's right! " ^ arg1 ^ "\n")
| args => print ("Too many arguments!\n")
val _ = main ()
Compiling and running this gives:
$ mosmlc args2.sml
$ ./a.out
Too few arguments!
$ ./a.out hello
That's right! hello
$ ./a.out hello world
Too many arguments!
A side note: The equivalent of C's argv[0] is CommandLine.name ().

Related

If statements questions in OCaml

I am trying to write the following code in OCaml:
let a = 0
let b = 1
if a > b then
{
print_endline "a";
print_endline "a";
}
print_endline "b"
And then I encountered the following error:
File "[21]", line 4, characters 0-2:
4 | if a > b then
^^
Error: Syntax error
I have tried using the begin and end keywords.
If you're writing a program (rather than mucking about in a REPL), then there are only certain constructs which can exist at the top level of your program.
One of those is a binding. So the following is fine:
let a = 0
let b = 1
But a conditional expression (if/else) is not permitted. We can get around this by binding that expression to a pattern. Since print_endline will just return (), we can write:
let () =
...
Your use of { and } is incorrect in this situation, but you can grouped multiple expressions with ; and ( and ). Remember that ; is not a "statement terminator" but rather a separator.
let () =
if a > b then (
print_endline "a";
print_endline "a"
);
print_endline "b"
Note that if can only exist without a matching else if the entire expression returns unit. This meets that criteria.

I am trying to read a string from stdin and flush it out to stdout but I can't find a Standard ML way

NOTE: I'm totally Newbie in Standard ML. I merely have basic F# knowledge.
This is a good ol' code in C
#include <stdio.h>
int main()
{
char str[100]; // size whatever you want
scanf("%s", str);
printf("%s\n", str);
return 0;
}
now, I want to make a Standard ML-version-equivalent of this code. so I tried this:
val str = valOf (TextIO.inputLine TextIO.stdIn)
val _ = print str
but my SML/NJ says this:
uncaught exception Option
raised at: smlnj/init/pre-perv.sml:21.28-21.34
I googled it, and I also searched this site, but I cannot find any solution which doesn't cause error.
does anyone knows it?
EDIT: I tried this code:
fun main =
let val str = valOf (TextIO.inputLine TextIO.stdIn)
in
case str
of NONE => print "NONE\n"
| _ => print str
end
but it also makes error:
stdIn:1.6-1.10 Error: can't find function arguments in clause
stdIn:4.9-6.33 Error: case object and rules don't agree [tycon mismatch]
rule domain: 'Z option
object: string
in expression:
(case str
of NONE => print "NONE\n"
| _ => print str)
This answer was pretty much given in the next-most recent question tagged sml: How to read string from user keyboard in SML language? -- you can just replace the user keyboard with stdin, since stdin is how you interact with the keyboard using a terminal.
So you have two problems with this code:
fun main =
let val str = valOf (TextIO.inputLine TextIO.stdIn)
in
case str
of NONE => print "NONE\n"
| _ => print str
end
One problem is that if you write fun main then it has to take arguments, e.g. fun main () = .... The () part does not represent "nothing" but rather exactly one thing, being the unit value.
The other problem is eagerness. The Option.valOf function will crash when there is no value, and it will do this before you reach the case-of, making the case-of rather pointless. So what you can do instead is:
fun main () =
case TextIO.inputLine TextIO.stdIn of
SOME s => print s
| NONE => print "NONE\n"
Using the standard library this can be shortened to:
fun main () =
print (Option.getOpt (TextIO.inputLine TextIO.stdIn, "NONE\n"))
I encourage you to read How to read string from user keyboard in SML language?

Why can I not print this input a second time in OCaml?

I am very new to OCaml and am attempting to learn and write a program at the same time. I am writing a palindrome program. I am attempting to get a string from the user such as d e v e d or Hello World! or loud all of the preceding are valid user input. I need to read these strings and display them then reverse them and check if it is a palindrome or not. I did the following code...
print_string "Enter a string: ";
let str = read_line () in
Printf.printf "%s\n" str;;
Printf.printf "%s\n" str;;
this works fine and will give the print, Enter a string: d e v e d or Enter a string: Hello World! The issue comes when I try to add another Printf.printf "%s\n" str;; into the code. it gives me an error of File "main.ml", line 5, characters 21-24:
Error: Unbound value str with line 5 being the line of the 2nd Printf.printf statement. I have tried this with no ; for both of the print statements, with 1 or with 2 and I get the same error each time. Does anyone with more OCaml knowledge know why I get this error.
Because of your use of in your code parses as:
(let str = read_line () in Printf.printf "%s\n" str);;
and then a completely separate:
Printf.printf "%s\n" str;;
So str is local to the first printf.
You want:
let str = read_line ();;
Printf.printf "%s\n" str;;
Printf.printf "%s\n" str;;
which is three separate definitions. The first defines a global variable str.

OCAML Taking multiple arguments from stdin and operating on them one by one

I have written an interpreter using ocamllex and ocamlyacc, the lexer and the parser work correctly but currently they only parse the last .txt argument it receives as oppose to all of them in turn. For example, ./interpret one.txt two.txt three.txt only parses three.txt as oppose to parsing one.txt and then two.txt and then three.txt which is what I want. So for example the parse results are as follows:
one.txt -> "1"
two.txt -> "2"
three.txt -> "3"
On calling ./interpret one.txt two.txt three.txt the current output is: 3 but I want it to be 123
Here is my main class which deals with the stdin and stdout
open Lexer
open Parser
open Arg
open Printf
let toParse c =
try let lexbuf = Lexing.from_channel c in
parser_main lexer_main lexbuf
with Parsing.Parse_error -> failwith "Parse failure!" ;;
let argument = ref stdin in
let prog p = argument := open_in p in
let usage = "./interpreter FILE" in
parse [] prog usage ;
let parsed = toParse !argument in
let result = eval parsed in
let _ = parsed in
flush stdout;
Thanks for your time
There's not really enough code here to be able to help.
If I assume that the output is written by eval, then I see only one call to eval. But there's nothing here that deals with filenames from the command line, so it's hard to say more.
If you are planning to read input from files, then there's no reason to be using stdin for anything as far as I can tell.
(I know this is a very minor point, but this code doesn't constitute a class. Other languages use classes for everything, but this is a module.)
Update
Here's a module that works something like the Unix cat command; it writes out the contents of all the files from the command line one after the next.
let cat () =
for i = 1 to Array.length Sys.argv - 1 do
let ic = open_in Sys.argv.(i) in
let rec loop () =
match input_line ic with
| line -> output_string stdout (line ^ "\n"); loop ()
| exception End_of_file -> ()
in
loop ();
close_in ic
done
let () = cat ()
Here's how it looks when you compile and run it.
$ ocamlc -o mycat mycat.ml
$ echo test line 1 > file1
$ echo test line 2 > file2
$ ./mycat file1 file2
test line 1
test line 2

How to use lexer generated by ocamllex

I have a trivial lexer taken from a tutorial (http://plus.kaist.ac.kr/~shoh/ocaml/ocamllex-ocamlyacc/ocamllex-tutorial/sec-ocamllex-some-simple-examples.html)
{ }
rule translate = parse
| "c" { print_string (Sys.getcwd ()); translate lexbuf }
| _ as c { print_char c; translate lexbuf }
| eof { exit 0 }
After generating the lexer OCaml and creating an executable,
ocamllex testlexer.mll && ocamlc -o testlexer testlexer.ml
I attempt to pass content in via stdin echo c | ./testlexer and via a file ./testlexer input, but neither works.
I also don't see any logic in the generated testlexer.ml for reading from stdin or a file, is it meant to be included as a module in another program or consumed by another code generation tool like ocamlyacc?
You need a main function (in essence). You can adapt it from the other examples on that page.
Here's a full example that I wrote up:
{ }
rule translate = parse
| "c" { print_string (Sys.getcwd ()); translate lexbuf }
| _ as c { print_char c; translate lexbuf }
| eof { exit 0 }
{
let main () =
let lexbuf = Lexing.from_channel stdin in translate lexbuf
let () = main ()
}
It seems to work as intended:
$ ocamllex l.mll
4 states, 257 transitions, table size 1052 bytes
$ ocamlc -o l l.ml
$ echo c/itworks | ./l
/home/jeffsco/tryll2/itworks
Update
Sorry, I forgot to answer your other questions. Yes, without the main function, the original code can be a module in a larger program. It could be a program that users ocamlyacc, or not.