Open Module_name gives a compiler-error - module

I cannot compile an extremely simple ocaml program test2.ml
open Test1
print_string " Hello "
with test1.ml containing only 1 line
type program = string
And test1.ml is compiled:
bash-3.2$ ocamlc test1.ml
bash-3.2$ ls test1.*
test1.cmi test1.cmo test1.ml
Anyone know why test1.ml does not compile?? Thank you.
More info. It's quite strange because, test2.ml compiles if I comment out its first line "open ..." OR
if I comment out its 3rd line "print_string..." but they cannot coexist!

Printing the error you received would have been helpful. For the reference, it's:
File "test2.ml", line 3, characters 0-12:
Error: Syntax error
The reason for this is a bit complex. The normal syntax is for a file to be a sequence of top-level statements, such as type definitions, let (without in), module definition/opening/including and so on.
Expressions such as print_string "Hello" are never treated as top-level statements unless the meaning is completely unambiguous, which 99% of the time involves separating them from the previous and following statement with a ;;
So, you could write the following:
open Test1 ;;
print_string " Hello "
And it would work. Most of the time, though, it is preferable to keep the file clean by turning the expression into a top-level let:
open Test1
let () = print_string " Hello "
This also has the benefit of making sure that the function returns unit, which is always nice to have.

Related

How to write a text prompt in Nim that has readline-style line editing?

readLine() doesn't support line editing and recalling previous commands, eg:
while true:
var name: string = readLine(stdin)
echo "Hi, ", name, "!"
Has no editing. But if I compile that and wrap it in rlwrap:
$ rlwrap read_test
It works as I hope. with editable and recallable lines, provided by the readline library.
readLineFromStdin() almost works, but doesn't support ctrl+d, it returns an empty string on ctrl+d, which is indistinguishable from a newline.
How can I do this in pure Nim? Thanks!
Ctrl+D is an EOF "signal", and thus you can catch the EOF in your input:
while not endOfFile(stdin):
var name: string = readLine(stdin)
echo "Hi, ", name, "!"
The procedure readLineFromStdin (https://github.com/nim-lang/Nim/blob/version-1-2/lib/impure/rdstdin.nim#L54) is not that complex, and you can re-write your own adding the above code to it.
While #xbello's answer is correct, if you want to use a package, we ended up using https://github.com/jangko/nim-noise, which supports C-d handling and loads of other features.

Why syntax error in this very simple print command

I am trying to run following very simple code:
open Str
print (Str.first_chars "testing" 0)
However, it is giving following error:
$ ocaml testing2.ml
File "testing2.ml", line 2, characters 0-5:
Error: Syntax error
There are no further details in the error message.
Same error with print_endline also; or even if no print command is there. Hence, the error is in part: Str.first_chars "testing" 0
Documentation about above function from here is as follows:
val first_chars : string -> int -> string
first_chars s n returns the first n characters of s. This is the same
function as Str.string_before.
Adding ; or ;; at end of second statement does not make any difference.
What is the correct syntax for above code.
Edit:
With following code as suggested by #EvgeniiLepikhin:
open Str
let () =
print_endline (Str.first_chars "testing" 0)
Error is:
File "testing2.ml", line 1:
Error: Reference to undefined global `Str'
And with this code:
open Str;;
print_endline (Str.first_chars "testing" 0)
Error is:
File "testing2.ml", line 1:
Error: Reference to undefined global `Str'
With just print command (instead of print_endline) in above code, the error is:
File "testing2.ml", line 2, characters 0-5:
Error: Unbound value print
Note, my Ocaml version is:
$ ocaml -version
The OCaml toplevel, version 4.02.3
I think Str should be built-in, since opam is not finding it:
$ opam install Str
[ERROR] No package named Str found.
I also tried following code as suggested in comments by #glennsl:
#use "topfind"
#require "str"
print (Str.first_chars "testing" 0)
But this also give same simple syntax error.
An OCaml program is a list of definitions, which are evaluated in order. You can define values, modules, classes, exceptions, as well as types, module types, class types. But let's focus on values so far.
In OCaml, there are no statements, commands, or instructions. It is a functional programming language, where everything is an expression, and when an expression is evaluated it produces a value. The value could be bound to a variable so that it could be referenced later.
The print_endline function takes a value of type string, outputs it to the standard output channel and returns a value of type unit. Type unit has only one value called unit, which could be constructed using the () expression. For example, print_endline "hello, world" is an expression that produces this value. We can't just throw an expression in a file and hope that it will be compiled, as an expression is not a definition. The definition syntax is simple,
let <pattern> = <expr>
where is either a variable or a data constructor, which will match with the structure of the value that is produced by <expr> and possibly bind variable, that are occurring in the pattern, e.g., the following are definitions
let x = 7 * 8
let 4 = 2 * 2
let [x; y; z] = [1; 2; 3]
let (hello, world) = "hello", "world"
let () = print_endline "hello, world"
You may notice, that the result of the print_endline "hello, world" expression is not bound to any variable, but instead is matched with the unit value (), which could be seen (and indeed looks like) an empty tuple. You can write also
let x = print_endline "hello, world"
or even
let _ = print_endline "hello, world"
But it is always better to be explicit on the left-hand side of a definition in what you're expecting.
So, now the well-formed program of ours should look like this
open Str
let () =
print_endline (Str.first_chars "testing" 0)
We will use ocamlbuild to compile and run our program. The str module is not a part of the standard library so we have to tell ocamlbuild that we're going to use it. We need to create a new folder and put our program into a file named example.ml, then we can compile it using the following command
ocamlbuild -pkg str example.native --
The ocamlbuild tool will infer from the suffix native what is your goal (in this case it is to build a native code application). The -- means run the built application as soon as it is compiled. The above program will print nothing, of course, here is an example of a program that will print some greeting message, before printing the first zero characters of the testing string,
open Str
let () =
print_endline "The first 0 chars of 'testing' are:";
print_endline (Str.first_chars "testing" 0)
and here is how it works
$ ocamlbuild -package str example.native --
Finished, 4 targets (4 cached) in 00:00:00.
The first 0 chars of 'testing' are:
Also, instead of compiling your program and running the resulting application, you can interpret your the example.ml file directly, using the ocaml toplevel tool, which provides an interactive interpreter. You still need to load the str library into the toplevel, as it is not a part of the standard library which is pre-linked in it, here is the correct invocation
ocaml str.cma example.ml
You should add ;; after "open Str":
open Str;;
print (Str.first_chars "testing" 0)
Another option is to declare code block:
open Str
let () =
print (Str.first_chars "testing" 0)

What is the perl6 equivalent of #INC, please?

I go
export PERL6LIB="/GitHub/perl6-Units/lib"
and then
echo $PERL6LIB
/GitHub/perl6-Units/lib
But when I run perl6 t/01-basic.t
use v6;
use Test;
plan 3;
lives-ok {
use Units <m>;
ok #Units::UNITS.elems > 0;
ok (0m).defined;
}
done-testing;
I still get an error
===SORRY!===
Could not find Units at line 8 in:
/Users/--me--/.perl6
/usr/local/Cellar/rakudo-star/2018.01/share/perl6/site
/usr/local/Cellar/rakudo-star/2018.01/share/perl6/vendor
/usr/local/Cellar/rakudo-star/2018.01/share/perl6
CompUnit::Repository::AbsolutePath<140707489084448>
CompUnit::Repository::NQP<140707463117264>
CompUnit::Repository::Perl5<140707463117304>
In Perl 5 I would have used print "#INC"; to see what paths are searched for the lib before the error is thrown. Using say flat $*REPO.repo-chain.map(*.loaded); either is before it loads or after it throws the exception.
Any help would be much appreciated - or maybe a hint on what to put in ~/.perl6 as I can't get a symlink to work either.
The error message itself is telling you what the library paths available are. You are failing to print them because you are expecting a run time action ( say ) to take place before a compile time error -- you could print out $*REPO at compile time, but again the exception is already showing you what you wanted.
$ PERL6LIB="/GitHub/perl6-Units/lib" perl6 -e 'BEGIN say $*REPO.repo-chain; use Foo;'
(file#/GitHub/perl6-Units/lib inst#/Users/ugexe/.perl6 inst#/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/site inst#/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/vendor inst#/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6 ap# nqp# perl5#)
===SORRY!===
Could not find Foo at line 1 in:
/GitHub/perl6-Units/lib
/Users/ugexe/.perl6
/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/site
/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6/vendor
/Users/ugexe/.rakudobrew/moar-2018.08/install/share/perl6
CompUnit::Repository::AbsolutePath<140337382425072>
CompUnit::Repository::NQP<140337350057496>
CompUnit::Repository::Perl5<140337350057536>
You can see /GitHub/perl6-Units/lib is showing up in the available paths, which is unlike your example. I'd question if your shell/env is actually setup correctly.

How to store a result to a variable in HP OpenVMS DCL?

I want to save the output of a program to a variable.
I use the following approach ,but fail.
$ PIPE RUN TEST | DEFINE/JOB VALUE #SYS$PIPE
$ x = f$logical("VALUE")
I got an error:%DCL-W-MAXPARM, too many parameters - reenter command with fewer parameters
\WORLD\
reference :
How to assign the output of a program to a variable in a DCL com script on VMS?
The usual way to do this is to write the output to a file and read from the file and put that into a DCL symbol (or logical). Although not obvious, you can do this with the PIPE command was well:
$ pipe r 2words
hello world
$ pipe r 2words |(read sys$pipe line ; line=""""+line+"""" ; def/job value &line )
$ sh log value
"VALUE" = "hello world" (LNM$JOB_85AB4440)
$
IF you are able to change the program, add some code to it to write the required values into symbols or logicals (see LIB$ routines)
If you can modify the program, using LIB$SET_SYMBOL in the program defines a DCL symbol (what you are calling a variable) for DCL. That's the cleanest way to do this. If it really needs to be a logical, then there are system calls that define logicals.

csh alias with variable number of arguments

I would like to create a csh alias that performs one operation if invoked without arguments and a second operation if invoked with a single argument. Does anyone know how to do this? (Attempting to refer to an argument that wasn't passed triggers an error).
I know this is a bit late but I just ran into needing something similar and hope it might still be relevant to somebody.
You can set the arguments as an array and query based on the size of the array:
alias testing 'set args_=(\!*); if ($#args_ > 0) echo "this command has $#args_ arguments" endif'
Aliases in tcsh are limited; for more advanced things, I've found that the best way is to source a (t)csh script, like so:
alias my-cmd 'source ~/.tcsh/my-cmd.tcsh'
And ~/.tcsh/my-cmd.tcsh would contain something like:
if ( $1 != '' ) then
echo "we have an argument: $1"
else
echo "we don't have an argument"
endif
Example output:
% my-cmd
we don't have an argument
% my-cmd hello
we have an argument: hello
Now, it may also be possible to do this with just an alias, but this will be much more maintainable & cleaner in the long run, IMHO.
(I've assumed tcsh here since almost all, or perhaps even all, c shells are tcsh these days).
Easy to do - sorry I'm late to the party.
alias iftest 'if (\\!:0 != \\!:$) echo "Last arg="\\!:$;if (\\!:0 == \\!:$) echo "No args given."'
This merely checks whether the 0th argument (=the 'iftest' itself) and the last arguments are the same, and if they are, assumes there is no argument. This is, of course, not necessarily true, but hopefully works in praxis.