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

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"

Related

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.

Unintuitive empty formatted string

I want to add a listener mechanism to a Format-based logging facility, and I ended up in a situation where my program is typed by OCaml and compiles, but the formatted string just disappeared, and I don't understand exactly why this happens (it's related to formatters returning unit when they should return something else, but I expected the program not to type-check in that case).
This comes from a real use case; its simplification may however have led into a somewhat contrived program.
The basic need is this: to devise a Format.printf-like function (with variadic arguments) that is easy to use but also allows other formatters to be notified (e.g. duplicating their outputs).
I've been told this is not possible due to typing constraints, and indeed if I further simplify my example below, I do get typing errors, but for some reason the program below does type-check but does not produce the expected result.
open Format
let observers : formatter list ref = ref []
let add_observer o : unit =
observers := o :: !observers
let print_to_fmt (fmt: formatter) (text: ('a, formatter, unit) format) : unit =
Format.fprintf fmt "<";
Format.fprintf fmt text;
Format.fprintf fmt ">#."
let notify text : unit =
List.iter (fun fmt ->
Format.printf "MESSAGE: {";
Format.printf text;
Format.printf "}#.";
print_to_fmt fmt text
) !observers
let buffer = ref ""
let append text _ _ = buffer := text
let print text =
let fmt = Format.make_formatter append (fun () -> ()) in
Format.kfprintf (fun f -> ()) fmt text
let log text =
notify text;
print text
let () =
add_observer (Format.err_formatter);
log "this works";
log "this does not %d" 42;
log "this also works"
Any help on how to (1) change the program to display this does not 42, or (2) an explanation on why the program type-checks when it seems it shouldn't, would be much appreciated.
You're trying to do a very strange magic with formatters, that I would classify as an abuse, honestly. Formatter is a formatted channel, not data, so they impose all problems of channels, like non-persistent data that disappear suddenly.
If you want to have a log function, that will dispatch data between registered formatters, then the following will work:
open Format
let observers : formatter list ref = ref []
let add_observer o : unit =
observers := o :: !observers
let notify (text : string) : unit =
List.iter (fun fmt ->
fprintf fmt "MESSAGE: {%s}#." text) !observers
let log text = ksprintf notify text
let () =
add_observer Format.err_formatter;
log "this works";
log "this does not %d" 42;
log "this also works"
Will rend the following output:
MESSAGE: {this works}
MESSAGE: {this does not 42}
MESSAGE: {this also works}

How to make a function with two strings as arguments

I'm not entirely sure what I'm doing wrong here. I have tested the code by input and output and it functions as desired no pun intended. :'P
I'm just not setting up this function correctly and I believe it's because my arguments happen to be desirably a string. Where if done correctly "CD" will be inserted into the middle of "ABEF". So, how do I go about doing this?
Thanks!
insertstr(ABEF, CD)
Function insertstr(string1, string2)
nostrmsg = "No string"
fullng = len(string1)
half = len(string1)/2
if half>0 then hfstr1 = mid(string1, 1, half)
str2lng = len(string2)
if str2lng>0 then paste = hfstr1+string2
lshalf = mid(string1, half+1, fullng)
if str2lng+half=str2lng+half then insert = paste+lshalf
End Function
Start with the knowledge that a functions returns a value, a tentative specification of what the function should do, and a basic testing skeleton:
Option Explicit
' returns the string build by inserting m(iddle) into f(ull) at half position
Function insertInto(f, m)
insertInto = "?"
End Function
Dim t, r
For Each t In Array( _
Array("ABEF", "CD", "ABCDEF") _
)
r = insertInto(t(0), t(1))
WScript.Echo t(0), t(1), r, CStr(r = t(2))
Next
output:
cscript 26873276.vbs
ABEF CD ? False
Then learn about Left, Mid, Len, and \ (integer division).
At last, re-write insertInto() so that the result starts with
cscript 26873276.vbs
ABEF CD ABCDEF True

OCaml simple interface based on user text input

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'

Reapeat/until help in lua

Hello I've been trying to get this code to work, I even cheated and added in the goal to my code and its still not accepting my answer, any suggestions?
-- Functions...
function p() -- For user imput..
print("Enter # and try to get the closest to it! (Valid range is 1-100)")
local var = tonumber(io.read())
if var == nil then
var = 0
end
return var
end
--Start main code..
-- Initialize the pseudo random number generator (I'm on windows...)
math.randomseed( os.time() )
math.random(); math.random(); math.random()
-- Setting goal
goal = math.random(1,100)
-- Guessing loop...
repeat
g = p()
print(g)
print(goal)
until g == Goal
print("YOU GUESSED THE GOAL!")
Replace the G by a lower case g.
until g == goal

Resources