OCaml main function - functional-programming

I need a main function to run the others functions.
I tried this:
let main () =
let deck = make_mazo in
let jugadores = players [] 0 in
dothemagic deck jugadores 0 [] [] [];;
But I got this error:
File "game.ml", line 329, characters 37-39:
Error: Syntax error
I think ;; is the problem and I need a different way to end the code. Also try with only ; and the problem is the same.
[EDIT]
An update here
let main =
let deck = make_mazo [] in
let game = players deck [] 0 in
let dd = fst game in
let jugadores = snd game in
dothemagic dd jugadores 0 [] [] [] [];
let () = main;;
Error persist:
File "game.ml", line 253, characters 13-15:
Error: Syntax error
The other functions are working perfectly fine, but i need a main function because I want to run the program with ocaml game.ml or ocamlbuild game.native
[SECOND EDIT]
After #camlspotter response: The use of ; of your code is wrong. Remove it.
Update 2.0
let main =
let deck = make_mazo [] in
let game = players deck [] 0 in
let dd = fst game in
let jugadores = snd game in
dothemagic dd jugadores 0 [] [] [] []
let () = main;;
New Error:
File "game.ml", line 253, characters 0-3: Error: Syntax error
Think let is the problem now, so i try with this
let main =
let deck = make_mazo [] in
let game = players deck [] 0 in
let dd = fst game in
let jugadores = snd game in
dothemagic dd jugadores 0 [] [] [] []
main;;
But Error is:
File "game.ml", line 253, characters 4-6:
Error: Syntax error

There's nothing syntactically wrong with the code you show here.
Most likely the problem is near the end of the part you don't show, like around line 324 of the file.
If I had to guess, I'd say that line 324 ends with in :-)
As a side comment, you'll also need to call this main function. You might want the last line of the file to be something like this:
let () = main ()
(This line appears in many of my OCaml projects.)

In ocaml, there is no main function unlike other languages, see the code below :
let () = print_string "hello\n";;
let f = print_string "hello, this is f\n";;
let () = f;;

OCaml programs, unlike programs in many other languages, do not have a specific entry-point: all the code in a module (file) is evaluated in order from top to bottom, sort of like in a scripting language. A common idiom you'll see is:
let name = "World" (* I could have added a ;; at the
* end of this line, but that would
* have been unnecessary *)
let () =
Printf.printf "Hello, %s!\n" name
which will output
Hello, World!
The let () = ... may seem a bit wonky, but it's really just pattern-matching: the return type of Printf.printf is unit, () is also of type unit, the you're really just saying "match this unit value with the result of evaluating this expression". Basically, this idiom means "run this unit-type expression in a safe way".
A similar, although highly discouraged, idiom, uses the catch-all pattern:
let greet s =
match s with
| "" -> false
| _ ->
Printf.printf "Hello, %s!\n" s;
true
let name = "World"
let _ =
greet world
The catch-all pattern doesn't care about the type (or value) of the expression it's being matched against, and this idiom means "run this expression and discard whatever it returned".

To solve my problem, I had to write the functions in the following way,
let fun x =
let y = blabla in
code_returning_unit; (* Use ; for unit returns *)
return_value;; (* Use ;; for end of fun *)
Thanks all for the help.

Related

How to share the information of logic variable between environment and use?

I'm trying to generate some annotations for functions. I have succeeded in implementing a plugin that achieves this purpose, but the problem that I am facing is that when I run tests on my plugin, an integrity check is executed automatically and I get an error that says:
Built-in logic variable \subset information is not shared between environment and use
To demonstrate this problem I have written a simplified plugin that will generate an ACSL annotation for a function called get_x().
The code for the simplified plugin is
open Cil_types
open Cil
module M = Plugin.Register
let my_emitter =
Emitter.create "Generate function contract" [ Emitter.Funspec ]
~correctness:[] ~tuning:[]
let construct_subset_ip e =
let t = Logic_utils.expr_to_term e in
let its =
[ Logic_const.tinteger 1; Logic_const.tinteger 2; Logic_const.tinteger 3 ]
in
let li = Cil_const.make_logic_info "\\subset" in
li.l_tparams <- [ "a" ];
let s1 = Cil_const.make_logic_var_formal "s1" Linteger in
let s2 = Cil_const.make_logic_var_formal "s2" Linteger in
li.l_profile <- [ s1; s2 ];
let tn1 = Tunion [ t ] in
let t1 = Logic_const.term tn1 Linteger in
let tn2 = Tunion its in
let t2 = Logic_const.term tn2 Linteger in
let p = Logic_const.papp (li, [], [ t1; t2 ]) in
Logic_const.new_predicate p
class my_visitor prj =
object (self)
inherit Visitor.generic_frama_c_visitor (Visitor_behavior.copy prj)
method! vglob_aux =
function
| GFun (fd, _) -> if fd.svar.vname = "get_x" then DoChildren else JustCopy
| _ -> JustCopy
method! vstmt_aux s =
match s.skind with
| Return (Some e, _) ->
let new_kf =
Option.get self#current_kf
|> Visitor_behavior.Get.kernel_function self#behavior
in
let bhv = Cil.mk_behavior ~name:"my_behavior" () in
let ip =
Visitor.visitFramacExpr self#frama_c_plain_copy e
|> construct_subset_ip
in
Queue.add
(fun () ->
Annotations.add_requires my_emitter new_kf ~behavior:"my_behavior"
[ ip ])
self#get_filling_actions;
Queue.add
(fun () -> Annotations.add_behaviors my_emitter new_kf [ bhv ])
self#get_filling_actions;
JustCopy
| _ -> JustCopy
end
let execute () =
ignore (File.create_project_from_visitor "ACSL annotated" (new my_visitor))
I applied this plugin on the following C module:
/* run.config
OPT: -autoload-plugins -sandbox
*/
int X;
int get_x() {
return X;
}
The output when executing the plugin on the C module is:
/* Generated by Frama-C */
int X;
/*# behavior my_behavior:
requires X ∈ {1, 2, 3}; */
int get_x(void)
{
return X;
}
Now, when I run $ ptest.opt tests\s1\test.c -show I get
...
[kernel] Parsing tests/s1/test.c (with preprocessing)
[kernel] tests/s1/test.c:8: Failure:
[AST Integrity Check]
AST of ACSL annotated
Built-in logic variable \subset information is not shared between environment and use
[kernel] Current source was: tests/s1/test.c:7
The full backtrace is:
Raised at Project.on in file "src/libraries/project/project.ml", line 405, characters 59-66
Called from File.init_project_from_visitor in file "src/kernel_services/ast_queries/file.ml", line 1818, characters 4-64
Called from File.create_project_from_visitor in file "src/kernel_services/ast_queries/file.ml", line 1842, characters 2-43
Called from Sandbox_visitor.execute in file "sandbox_visitor.ml", line 60, characters 9-77
Called from Stdlib__Queue.iter.iter in file "queue.ml", line 121, characters 6-15
Called from Boot.play_analysis in file "src/kernel_internals/runtime/boot.ml", line 36, characters 4-20
Called from Cmdline.play_in_toplevel_one_shot in file "src/kernel_services/cmdline_parameters/cmdline.ml", line 846, characters 2-9
Called from Cmdline.play_in_toplevel in file "src/kernel_services/cmdline_parameters/cmdline.ml", line 876, characters 18-64
Called from Cmdline.catch_toplevel_run in file "src/kernel_services/cmdline_parameters/cmdline.ml", line 235, characters 4-8
Frama-C aborted: internal error.
Please report as 'crash' at https://git.frama-c.com/pub/frama-c/issues
Your Frama-C version is 24.0 (Chromium).
Note that a version and a backtrace alone often do not contain enough
information to understand the bug. Guidelines for reporting bugs are at:
https://git.frama-c.com/pub/frama-c/-/wikis/Guidelines-for-reporting-bugs
What is this error about, and how do I solve it?
PS: Excuse me for any bad coding practices that you might notice. I'm a beginner in both Ocaml and Frama-C.

F# Console.ReadLine not waiting for input

I'm new to F#, apologies if I'm missing something obvious here.
I have the following code, with the intent to get user input and convert it to a uint:
let println ln =
printfn "%s" ln
let rec getUserKeyInput =
let x = System.Console.ReadKey()
string x
let getInputWithPrompt prompt =
println prompt
getUserKeyInput
let rec getUserUIntFromStr str =
try
let i = str |> uint
i
with
| :? System.FormatException -> println "Please enter a positive integer";
(getUserUIntFromStr (getUserKeyInput))
When getUserUIntFromStr is called with let i = getUserUIntFromStr str "Please enter a positive integer" is printed infinitely. I've also tried Console.ReadLine() and stdin.ReadLine(), both in interactive and from main, with the same results. It looks to me like none of the "Read" functions are waiting for input, but that doesn't seem right and I'm guessing I've done something wrong. Any suggestions?
getUserKeyInput is a value, not a function. It's evaluated only once at init time, not every time you reference it.
To make it a function, you need to give it a parameter. What type of parameter? Well, technically any type will do, but F# has you covered: for situations where you need to have some value, but there isn't a sensible value to use (which happens surprisingly often), there is a special type unit with a single value denoted as parentheses ():
let getUserKeyInput () =
let x = System.Console.ReadKey()
string x
(also note that rec is unnecessary, because the function isn't actually recursive)
(also note that ReadKey takes such parameter as well - it's the same deal there)
And then pass the parameter to call the function:
println "Please enter a positive integer"
getUserUIntFromStr (getUserKeyInput ())

Handle recursive function within an other function ocaml

If I have one or more recursive functions inside an Ocaml function how can I call them without exit from the main function taking their value as return of the main function?
I'm new in Ocaml so I'll try to explain me better...
If I have :
let function =
let rec recursive1 = ...
...
let rec recursive2 = ...
...
How can I call them inside function to tell it "Hey, do you see this recursive function? Now call it and takes its value."
Because my problem is that Ocaml as return of my functions sees Unit instead of the right return.
I will post the code below :
let change k v list_ =
let rec support k v list_ =
match list_ with
| [] -> []
| (i,value) :: tl -> if i = k
then (k,v) :: tl
else (i,value) :: support k v tl in
let inserted = support k v list_ in inserted
let () =
let k = [ (1,"ciao");(2,"Hola");(3,"Salut") ] in
change 2 "Aufwidersen" k
Change takes as input a key, a value and a (int * string )list and should return the same list of the input but changing the value linked to the key selected ( if in list ).
support, instead, makes the dirty job. It builds a new list and when k is found i = k it changes value and attach the tile, closing the function.
The return of change is unit when it should be (int * string) list. I think because inserted isn't taken as return of the function.
change does not return unit. The error in fact tells you exactly the opposite, that it returns (int * string) list but that it expects unit. And it expects unit because you're assigning it to a () pattern.
I don't know what you actually intend to do with the return value, as right now you don't seem to care about it, but you can fix the error by just assigning it to a name:
let result: (int * string) list =
let k = [ (1,"ciao");(2,"Hola");(3,"Salut") ] in
change 2 "Aufwidersen" k
Since it's not used I've added a type annotation to make sure we're getting what we expect here, as otherwise result could be anything and the compiler wouldn't complain. You don't typically need this if you're going to use result however, as you'd then get an error if the type doesn't unify with its usage.

Function with an arbitrary number of arguments in F#

I want to write a function that will take an arbitrary number of (curried) arguments and simply print them out (or perform some other unspecified action with them). Here is what I have come up with:
let print arg =
let rec print args arg =
if not (FSharpType.IsFunction(typeof<'t>)) then
printfn "%A" args
Unchecked.defaultof<'t>
else
print (box arg::args)
print []
When I try to compile this I get the error The resulting type would be infinite when unifying ''t' and ''a -> 't.
I know I could just pass the arguments as a list, but I am trying to develop an API of sorts where this would be a useful idiom to have.
Is there some clever compiler trick to make such a function possible in F# or is it a lost cause?
It seems that the two branches of the inner print want to return different types: the "then" part wants to return 't, but the "else" part wants to return 'a -> 't, where 't is necessarily the same in both branches. That is, your function tries to return either its own return type or a function from another type to its own return type. Such combined return type would, indeed, be infinite, which is in perfect accordance with what you set out to do - namely, create a function with infinite number of arguments. Though I do not know how to formally prove it, I would say this is indeed impossible.
If your goal is to simply create a list of boxed values, you could get away with defining a few infix operators.
let (<+>) a b = a # [(box b)]
let (<&>) a b = [(box a); (box b)]
let xs = 5 <&> "abc" <+> 3.0 <+> None <+> true
>> val xs : obj list = [5; "abc"; 3.0; null; true]
Alternatively, with carefully chosen operator precedence, you can apply a function (but then you'll need a terminator):
let (^>) a b = (box a)::b
let (<&>) f xs = f xs
let print xs = sprintf "%A" xs
let xs = print <&> 5 ^> "abc" ^> 3.0 ^> None ^> true ^> []
>> val xs : string = "[5; "abc"; 3.0; null; true]"

How to convert a string to integer list in ocaml?

I need to pass two list as command line arguments in ocaml.
I used the following code to access it in the program.
let list1=Sys.argv.(1);;
let list2=Sys.argv.(2);;
I need to have the list1 and list2 as list of integers.
I am getting the error
This expression has type string but an expression was expected of type
int list
while processing.
How can I convert that arguments to a list of integers.
The arguments are passed in this format [1;2;3;4] [1;5;6;7]
Sys.argv.(n) will always be a string. You need to parse the string into a list of integers. You could try something like this:
$ ocaml
OCaml version 4.01.0
# #load "str.cma";;
# List.map int_of_string (Str.split (Str.regexp "[^0-9]+") "[1;5;6;7]");;
- : int list = [1; 5; 6; 7]
Of course this doesn't check the input for correct form. It just pulls out sequences of digits by brute force. To do better you need to do some real lexical analysis and simple parsing.
(Maybe this is obvious, but you could also test your function in the toplevel (the OCaml read-eval-print loop). The toplevel will handle the work of making a list from what you type in.)
As Sys.argv is a string array, you need to write your own transcription function.
I guess the simplest way to do this is to use the Genlex module provided by the standard library.
let lexer = Genlex.make_lexer ["["; ";"; "]"; ]
let list_of_string s =
let open Genlex in
let open Stream in
let stream = lexer (of_string s) in
let fail () = failwith "Malformed string" in
let rec aux acc =
match next stream with
| Int i ->
( match next stream with
| Kwd ";" -> aux (i::acc)
| Kwd "]" -> i::acc
| _ -> fail () )
| Kwd "]" -> acc
| _ -> fail ()
in
try
match next stream with
| Kwd "[" -> List.rev (aux [])
| _ -> fail ()
with Stream.Failure -> fail ()
let list1 = list_of_string Sys.argv.(1)
let list2 = list_of_string Sys.argv.(2)
Depending on the OCaml flavor you want to use, some other library may look more interesting. If you like yacc, Menhir may solve your problem in a few lines of code.

Resources