OCaml simple interface based on user text input - user-interface

I'm trying to create a very simple user interface for my Binary Search Tree project.
I've done all the necessary functions for the BST but my problem is that I can't get a hold on how to reference to a tree variable inside the program so that I can update it and pass it through each program call.
let rec interface endCondition tree =
let option = read_int ()
in
if option = endCondition then
let () = print_string "Thank you for using the program!" in
let () = print_newline ()
in print_newline ()
else
let () =
if option = 1 then
let value = read_int ()
(* line I'm having problems with *)
in let tree = insert tree value
in let () = Printf.printf "Inserted Node: %d" value
in print_newline ()
else if option = 2 then
let () = print_string "Search Node:"
(* search code here *)
in print_newline ()
else
let () = print_string "Lower"
in print_newline ()
in interface endCondition tree;;
Whenever I use the let function it creates a new variable. How can I use the tree passed as parameter?
Thank you very much!

You need to pass the new tree up farther so you can get at it at the end, something like this:
else
let tree' =
if option = 1 then let ... in insert tree value
else if option = 2 then let ... in tree
else let .... in tree
in interface endCondition tree'

Related

How can I factor multiples function that gets their result process by another function?

I would like to factorize this code :
(* This function is applied to the result of functions below *)
let manage_result r s =
match r with
| Error ( `Msg e ) -> Tsdl.Sdl.log s e;exit 1
| Ok a -> a
(* Examples of function I want to factorize, let's call them f_functions, f for factorize *)
let init () =
let flag = Tsdl.Sdl.Init.everything in
let result = Tsdl.Sdl.init flag in
manage_result result "Init error : %s"
let create_window title w h =
let flag = Tsdl.Sdl.Window.windowed in
let result = Tsdl.Sdl.create_window title ~w:w ~h:h flag in
manage_result result "Create window error : %s"
let get_window_surface window =
let result = Tsdl.Sdl.get_window_surface window in
manage_result result "Get window surface error : %s"
As you can see, the two last lines of all of these f_functions are very similar. I would like to make a function that takes as argument a function ( for example, if I wanted to factorize init, the function passed as a parameter would be Tsdl.Sdl.init) and return a function that return the return value of function passed as an argument AND processed through manage_result.
The difficulty is that I don't know how many argument can the f_functions take.
Any other recommendations is appreciated!
Thank you.
A potential solution might be to use the pipe operator rather than naming the intermediary result
let on_error s r = manage_result r s
let create_window title w h =
let flag = Tsdl.Sdl.Window.windowed in
Tsdl.Sdl.create_window title ~w:w ~h:h flag
|> on_error "Create window error : %s"
Going one step further, we could define a custom operator for the error handling
let ( <!> ) = manage_result
which may make your definition lightweight enough
let create_window title w h =
let flag = Tsdl.Sdl.Window.windowed in
Tsdl.Sdl.create_window title ~w:w ~h:h flag
<!> "Create window error : %s"

What does Some() do on the left hand side of a variable assignment?

I was reading some Rust code and I came across this line
if let Some(path) = env::args().nth(1) {
Inside of this function
fn main() {
if let Some(path) = env::args().nth(1) {
// Try reading the file provided by the path.
let mut file = File::open(path).expect("Failed reading file.");
let mut content = String::new();
file.read_to_string(&mut content);
perform_conversion(content.as_str()).expect("Conversion failed.");
} else {
println!(
"provide a path to a .cue file to be converted into a MusicBrainz compatible tracklist."
)
}
}
The line seems to be assigning the env argument to the variable path but I can't work out what the Some() around it is doing.
I took a look at the documentation for Option and I understand how it works when used on the right hand side of = but on the left hand side I am a little confused.
Am I right in thinking this line is equivalent to
if let path = Some(env::args().nth(1)) {
From the reference :
An if let expression is semantically similar to an if expression but
in place of a condition expression it expects the keyword let followed
by a refutable pattern, an = and an expression. If the value of the
expression on the right hand side of the = matches the pattern, the
corresponding block will execute, otherwise flow proceeds to the
following else block if it exists. Like if expressions, if let
expressions have a value determined by the block that is evaluated.
In here the important part is refutability. What it means refutable pattern in here it can be in different forms. For example :
enum Test {
First(String, i32, usize),
Second(i32, usize),
Third(i32),
}
You can check the x's value for a value for 3 different pattern like :
fn main() {
let x = Test::Second(14, 55);
if let Test::First(a, b, c) = x {}
if let Test::Second(a, b) = x {} //This block will be executed
if let Test::Third(a) = x {}
}
This is called refutability. But consider your code like this:
enum Test {
Second(i32, usize),
}
fn main() {
let x = Test::Second(14, 55);
if let Test::Second(a, b) = x {}
}
This code will not compile because x's pattern is obvious, it has single pattern.
You can get more information from the reference of refutability.
Also you are not right thinking for this:
if let path = Some(env::args().nth(1)) {
Compiler will throw error like irrefutable if-let pattern because as the reference says: "keyword let followed by a refutable pattern". In here there is no refutable pattern after "let". Actually this code tries to create a variable named path which is an Option and this make no sense because there is no "If" needed,
Instead Rust expects from you to write like this:
let path = Some(env::args().nth(1)); // This will be seem like Some(Some(value))
The other answers go into a lot of detail, which might be more than you need to know.
Essentially, this:
if let Some(path) = env::args().nth(1) {
// Do something with path
} else {
// otherwise do something else
}
is identical to this:
match env::args().nth(1) {
Some(path) => { /* Do something with path */ }
_ => { /* otherwise do something else */ }
}

Integrating GTK and Lwt

I am working on a program in which I would like to use lablgtk and lwt. I have functions fetching data on lwt threads, then I would like to display the data in a GUI using lablgtk. I am struggling with the integration of lablgtk in the lwt framework. Below is a distilled version that demonstrates my problem which is that I can get the GUI to launch, but then nothing else happens. Any help is greatly appreciated.
(* gtk_and_lwt.ml *)
let (>>=) = Lwt.bind
let locale = GtkMain.Main.init ()
let window = GWindow.window ~width:300 ~height:200 ()
let vbox = GPack.vbox ~border_width:2 ~packing:window#add ()
let my_table =
GPack.table
~rows:1
~columns:2
~row_spacings:5
~col_spacings:5
~border_width:5
~packing:vbox#pack
()
let _ =
GMisc.label
~text:"User Input"
~packing:(my_table#attach ~left:0 ~top:1 ~right:1 ~bottom:2)
()
let my_label =
GMisc.label
~text:"Fetching User Input..."
~packing:(my_table#attach ~left:1 ~top:0 ~right:2 ~bottom:1)
()
let rec get_user_input () =
Lwt_io.read_line Lwt_io.stdin
>>= fun s -> my_label#set_text s |> Lwt.return
>>= get_user_input
let main () =
(* Kill the process when the user clicks the "X" button in top left cornet*)
let _ = window#connect#destroy ~callback:GMain.Main.quit in
window#show ();
Lwt.async (get_user_input);
Lwt.return ## GMain.Main.main ()
let _ = Lwt_main.run ## main ()
I am compiling with ocamlfind ocamlc -g -package lwt,lwt.syntax,lwt.unix,lablgtk2 -linkpkg gtk_and_lwt.ml -o GtkAndLwt

Is it possible to use a member instead of let for an F# Event?

In this code, EventL uses a let binding and EventM (is an attempt to) use a member:
type MyType() =
let EventL = new Event<_>()
member this.EventM = new Event<_>()
member this.AddHandlers() =
Event.add (fun string1 -> printfn "EventL: %s" string1) EventL.Publish
Event.add (fun string1 -> printfn "EventM: %s" string1) this.EventM.Publish
member this.Trigger(message) =
EventL.Trigger(message)
this.EventM.Trigger(message)
let myMyType = MyType()
myMyType.AddHandlers()
myMyType.Trigger("Event arg.")
When run, this outputs only EventL: Event arg. while EventM's handler is not called.
Am I making a silly mistake or missing some piece of logic regarding members?
Your EventM is a computed property that gets evaluated every time it's called. This results in different Event objects being created throughout the rest of your code (2 times, once in AddHandlers, next in Trigger).
Checkout the member val syntax. That creates a backing field and still gives public accessibility.
The fixed version would be:
type MyType() =
member val EventM = new Event<_>()
If you don't have a primary constructor then you will need to use val instead and assign it in your constructor:
type MyType =
val EventM : Event<string>
new () = { EventM = new Event<_>() }
Note that in this case, you will have to give the type argument to Event.

Getting an swift class var without Optional("value")

I'm creating a utility to add archival events to a calendar.
example run
./create-events-from-dvd-contents.swift --path /Volumes/ARCHIVE/DVD\ 1255/2451-01_LLA_Assets\ Folder\ Nov\ 2015/
Optional("DVD 1255")
The class is
class Event {
var location: String? ;
var start: String? ;
var notes: String? ;
}
The code to print the dvd location is
let event = Event() ;
let pathArray = path.characters.split {$0 == "/"}.map { String($0) } ;
event.location = pathArray[2] ;
print(event.location) ;
What is the simplest way to get 'DVD 1255' output instead of 'Optional("DVD 1255")'?
you must unwrap the value first into its own (non optional) variable.
let event = Event() ;
let pathArray = path.characters.split {$0 == "/"}.map { String($0) } ;
event.location = pathArray[2];
if let location = event.location {
print(location);
}
or you could put an ! after event.location if you wanted.
let event = Event() ;
let pathArray = path.characters.split {$0 == "/"}.map { String($0) } ;
event.location = pathArray[2] ;
print(event.location!) ;
The nil-coalescing operator is a clean way to do this:
var x: String? = "foo"
print(x) // Optional('foo')
x = nil
var y: String = x ?? "bar" // note y is not an optional
print(y) // Bar
print(x ?? "Not optional") // Not optional
Also, I noticed you are using semi-colons, which are unnecessary in Swift. I mention this, not as an opinion, but because it is a good practice of Swift to not use semi-colons unless necessary (multiple statements on one line or something)

Resources