Hi can someone help me figure why i get the
ERROR: Inserting EQUALOP
for the following code?
fun generator inchan outchan n = if n>0
then
(let
fun loop () =
val c = recv(outchan)
val _ = send (inchan, c)
in
(loop ();(generator inchan outchan (n-1)))
end)
else inchan;
You enter a let statement, and then define a function. However, inside that function, you
seem to want to define more variables. To do this, you need another let statement. Without it, you will get a syntax error like this.
Try using this instead:
fun loop () = send (inchan, recv (outchan))
Or, if you want the separate lines for more clarity:
fun loop () =
let
val c = recv (outchan)
in
send (inchan, c)
end
Or maybe
fun loop () =
let
val c = recv (outchan)
val _ = send (inchan, c)
in
()
end
Related
I am attempting to implement a basic 'stress testing' program in MLton and its Concurrent ML implementation, specifically the Monte Carlo Pi test described here. While I think I have most of what I need figured out, I have a problem in that my program always terminates before the CML threads have finished their work. I know that they are doing something, since I sometimes see them print text to the console that I have directed should be printed, but there seems to be a race condition between them getting started and running, and the program as a whole exiting.
The code where I start CML is:
local
val iterations : int = 10
val num_threads : int = 1
val still_going : bool ref = ref true
in
val _ = (RunCML.doit ((experiment iterations num_threads still_going), NONE);
(* while !still_going do (); (* Spin-wait for the CML stuff to finish. This doesn't work... *) *)
print "All done!\n")
end
the contents of the experiment function are:
fun experiment (iterations : int) (num_threads : int) (still_going : bool ref) () : unit = let
val iters_per_thread : int = iterations div num_threads
val return_ivars = Vector.tabulate (num_threads, (fn _ => SyncVar.iVar()))
val _ = Vector.map (fn return_ivar => CML.spawn (montecarlopi iters_per_thread return_ivar)) return_ivars
val return_val = Vector.foldl (fn (elem, acc) => acc + (SyncVar.iGet elem)) 0.0 return_ivars
in
(TextIO.print ("Result is: " ^ (Real.toString return_val) ^ "\n");
still_going := false)
end
and finally, the montecarlopi function is:
fun montecarlopi (iterations : int) (return_ivar : real SyncVar.ivar) () = let
val _ = MLton.Random.srand (valOf (MLton.Random.useed ()))
fun helper accumulator 0 = accumulator
| helper accumulator iteration = let
val x : real = wordToBoundedReal (MLton.Random.rand ())
val y : real = wordToBoundedReal (MLton.Random.rand ())
val in_target = (x * x) + (y * y)
val next_iter = iteration - 1
val _ = TextIO.print ("next_iter is: " ^ (Int.toString next_iter) ^ ", in_target is: " ^ (Real.toString in_target) ^ ",x is: " ^ (Real.toString x) ^ ",y is: " ^ (Real.toString y) ^ "\n")
in
if in_target < 1.0 then
helper (accumulator + 1) next_iter
else
helper accumulator next_iter
end
in
SyncVar.iPut (return_ivar, (4.0 * ((real (helper 0 iterations)) / (real iterations))))
end
(The full (small) program and accompanying .mlb file can be viewed here). I'm reasonably sure that the bits inside the RunCML.doit function call do what they're supposed to, which leads me to think that the issue is probably to do with the outermost part of the program.
As you can see, I tried to spin wait, using a ref cell on a boolean to determine when to stop, but that doesn't seem to work. Nor does trying to spin wait using RunCML.isRunning - although both of those sound like terrible ideas to begin with, really, anyway. Of course, I can't use something like a CML channel or syncvar, since those need to be inside the RunCML.doit segment to be used. Changing the number of threads doesn't make any difference to this problem. Nor was I able to find any other functions that would make the main part go into a non-blocking wait.
How do I get the outer part of my program to wait until the bulk of it, inside the RunCML.doit function call, completes? Or, am I doing something wrong inside that part, which is causing the problem?
If we look at the the function RunCML.doit, It has type OS.Process.status which can either be success or failure, from which your call to doit is returning failure. There is a CML function shutdown: OS.Process.status -> 'a.
Which could be an explaination for why it's failing, except you don't call shutdown, and parts of your output results never print.
Here is a small example exercising various mechanisms for CML's shutdown, where CML seems to be doing something such as 'graceful' internally. Catching exceptions raised and turning those into failure.
structure Main = struct
open CML
structure RunCML = RunCML;
exception ohno
fun raises() = raise ohno
fun succeed() = RunCML.shutdown(OS.Process.success)
fun fail() = RunCML.shutdown(OS.Process.failure)
fun graceful f () =
let val () = f() handle _ => RunCML.shutdown(OS.Process.failure);
in RunCML.shutdown(OS.Process.success)
end
fun print_status status =
if OS.Process.isSuccess status
then TextIO.print("success\n")
else TextIO.print("failure\n")
fun main() = let
val _ = TextIO.print(banner ^ "\n");
val _ = print_status(RunCML.doit(succeed, NONE))
val _ = print_status(RunCML.doit(fail, NONE))
val _ = print_status(RunCML.doit(raises, NONE))
val _ = print_status(RunCML.doit(graceful(raises), NONE))
val _ = print_status(RunCML.doit(graceful(succeed), NONE))
in OS.Process.success end
end
So, if CML is exiting strangely, and you aren't calling shutdown yourself, its a good chance there is an exception being raised somewhere, which turned out to be the case.
One way to avoid this silent handling of exceptions might in the future might be adding something like:
fun noisy f () =
let val () = f()
handle e =>
let val () = TextIO.print ("Exception: " ^ (exnName e)
^ " Message: " ^ (exnMessage e) ^ "\n")
in RunCML.shutdown(OS.Process.failure) end
in RunCML.shutdown(OS.Process.success)
end
then calling RunCML.doit(noisy(f), NONE)
P.S. Thank you for including a link to your code, it would have been much harder to understand the problem otherwise.
I have the following code block which I modified from the mirageOS github repo:
open Lwt.Infix
module Main (KV: Mirage_kv.RO) = struct
let start kv =
let read_from_file kv =
KV.get kv (Mirage_kv.Key.v "secret") >|= function
| Error e ->
Logs.warn (fun f -> f "Could not compare the secret against a known constant: %a"
KV.pp_error e)
| Ok stored_secret ->
Logs.info (fun f -> f "Data -> %a" Format.pp_print_string stored_secret);
in
read_from_file kv
end
This code reads data from a file called "secret" and outputs it once. I want to read the file and output from it constantly with sleep in between.
The usage case is this: While this program is running I will update the secret file with other processes, so I want to see the change in the output.
What I tried ?
I tried to put the last statement in while loop with
in
while true do
read_from_file kv
done
But It gives the error This expression has type unit Lwt.t but an expression was expected of type unit because it is in the body of a while loop.
I just know that lwt is a threading library but I'm not a ocaml developer and don't try to be one, (I'm interested in MirageOS) , so I can't find the functional syntax to write it.
You need to write the loop as a function. e.g.
let rec loop () =
read_from_file kv >>= fun () ->
(* wait here? *)
loop ()
in
loop ()
I am trying to understand Ocaml and running following code from here:
let rec fib n =
if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main () =
let arg = int_of_string Sys.argv.(1) in
print_int (fib arg);
print_newline ();
exit 0;;
main ();;
However, I cannot understand why () and in are needed and why following code (which is much cleaner) does not work:
let rec fib n =
if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main =
let arg = int_of_string Sys.argv.(1);
print_int (fib arg);
print_newline;
exit 0;; (* Line 7. Error is coming from here.*)
main;;
Above code gives following error:
File "fib_simpler.ml", line 7, characters 8-10:
Error: Syntax error
I notice that removing () only give warning, while removing in gives error and program execution stops.
Keeping in and () after print_newline removes all warnings and errors. So () is not really needed with main keywords.
Above is shown in comments below:
let rec fib n = (*(n) also works here*)
if n < 2 then 1 else fib (n-1) + fib (n-2);;
let main () = (*removing () here does not matter*)
let arg = int_of_string Sys.argv.(1) in (* in keyword is essential here*)
print_int (fib arg);
print_newline (); (*removing () causes warning *)
exit 0;;
main ();; (*removing () here does not matter*)
Any explanation will be appreciated.
OCaml is an expression-based language. It does not have statements, and therefore ; is not a statement terminator, but a sequence operator (similar to the comma operator of C). <expr1>; <expr2> is approximately just a short-hand for let () = <expr1> in <expr2>. It evaluates expr1, discards its value, then evaluates expr2 and returns that value.
let <pattern> = <expr1> in <expr2> is an expressions which binds the result of expr1 according to <pattern>, which may just be a simple identifier or a more complex record pattern for example, in the context of expr2. The bindings created by <pattern> will not exist outside expr2.
Using (), called "unit" in a binding defines a function. If you omit the argument, you're not defining a function, just a value. The difference is that a value is evaluated immediately, and just once, while a function will be evaluated when it is "called" by applying arguments to it. A function that expects () as an argument must be given () as the argument to execute it, otherwise you're just passing the function itself around. And if you're just discarding it, as you do above, that is almost always an error. Hence the warning.
In short:
let arg = int_of_string Sys.argv.(1); ... without an in separating two expressions is a syntax error. The compiler just doesn't realize it until it gets to the end of the current expression and discovers there is no in to be found there.
let main () =... defines a function
let main = ... defines a value
print_newline (); ... applies the argument () to print_newline, thereby executing it, then discards the return value
print_newline; ... doesn't really do anything
Finally, if you're just going to execute main once, you can reduce
let main () = ...;;
main;;
to
let () = ...;;
You don't need a named function unless you're going to use it multiple times.
I'm very new to SML and I'm trying to add some items to a list
fun foo(inFile : string, outFile : string) = let
val file = TextIO.openIn inFile
val outStream = TextIO.openOut outFile
val contents = TextIO.inputAll file
val lines = String.tokens (fn c => c = #"\n") contents
val lines' = List.map splitFirstSpace lines
fun helper1(lis : string list) =
case lis of
[] => ( TextIO.closeIn file; TextIO.closeOut outStream)
| c::lis => ( TextIO.output(outStream, c);
helper1(lis))
fun helper(lis : (string * string) list, stack : string list) =
case lis of
[] => stack
| c::lis => ( act(#1 c, #2 c)::stack;
helper(lis, stack))
val x = helper(lines', [])
in
helper1(x)
end;
I'm getting a blank output file whenever I run the code and I'm having trouble figuring out why but I do know that the helper function is getting the proper values from the "act" function because I tested it by using print(action(...))
Thanks
The problem is with this part:
( act(#1 c, #2 c)::stack; helper(lis, stack) )
This is creating a new list and then immediately throwing it away before performing the recursive call. What you want to do instead is
helper(lis, act(#1 c, #2 c)::stack)
Additional hint: both your helper functions can be replaced by simple uses of List.app and List.foldl.
Edit: Further hint: In fact, you can write that as just
helper(lis, act(c)::stack)
because a function with "two arguments" is simply a function taking a pair.
I have a function save that take standard input, which is used individually like this:
./try < input.txt (* save function is in try file *)
input.txt
2
3
10 29 23
22 14 9
and now i put the function into another file called path.ml which is a part of my interpreter. Now I have a problem in defining the type of Save function and this is because save function has type in_channel, but when i write
type term = Save of in_channel
ocamlc complain about the parameter in the command function.
How can i fix this error? This is the reason why in my last question posted on stackoverflow, I asked for the way to express a variable that accept any type. I understand the answers but actually it doesn't help much in make the code running.
This is my code:
(* Data types *)
open Printf
type term = Print_line_in_file of int*string
| Print of string
| Save of in_channel (* error here *)
;;
let input_line_opt ic =
try Some (input_line ic)
with End_of_file -> None
let nth_line n filename =
let ic = open_in filename in
let rec aux i =
match input_line_opt ic with
| Some line ->
if i = n then begin
close_in ic;
(line)
end else aux (succ i)
| None ->
close_in ic;
failwith "end of file reached"
in
aux 1
(* get all lines *)
let k = ref 1
let first = ref ""
let second = ref ""
let sequence = ref []
let append_item lst a = lst # [a]
let save () =
try
while true do
let line = input_line stdin in
if k = ref 1
then
begin
first := line;
incr k;
end else
if k = ref 2
then
begin
second := line;
incr k;
end else
begin
sequence := append_item !sequence line;
incr k;
end
done;
None
with
End_of_file -> None;;
let rec command term = match term with
| Print (n) -> print_endline n
| Print_line_in_file (n, f) -> print_endline (nth_line n f)
| Save () -> save ()
;;
EDIT
Error in code:
Save of in_channel:
Error: This pattern matches values of type unit
but a pattern was expected which matches values of type in_channel
Save of unit:
Error: This expression has type 'a option
but an expression was expected of type unit
There are many errors in this code, so it's hard to know where to start.
One problem is this: your save function has type unit -> 'a option. So it's not the same type as the other branches of your final match. The fix is straightforward: save should return (), not None. In OCaml these are completely different things.
The immediate problem seems to be that you have Save () in your match, but have declared Save as taking an input channel. Your current code doesn't have any way to pass the input channel to the save function, but if it did, you would want something more like this in your match:
| Save ch -> save ch
Errors like this suggest (to me) that you're not so familiar with OCaml's type system. It would probably save you a lot of trouble if you went through a tutorial of some kind before writing much more code. You can find tutorials at http://ocaml.org.