companion_cube changed the topic of #ocaml to: Discussion about the OCaml programming language | http://www.ocaml.org | OCaml 5.2.0 released: https://ocaml.org/releases/5.2.0 | Try OCaml in your browser: https://try.ocamlpro.com | Public channel logs at https://libera.irclog.whitequark.org/ocaml/
TCZ has quit []
humasect has joined #ocaml
tomku has quit [Ping timeout: 244 seconds]
humasect has quit [Quit: Leaving...]
tomku has joined #ocaml
mbuf has joined #ocaml
trillion_exabyte has quit [Ping timeout: 252 seconds]
trillion_exabyte has joined #ocaml
dev2 has quit [Quit: WeeChat 4.3.2]
<discocaml> <jo.blade> Hello, I need some help about how to do network caching in a purely functional manner. In my case I have a function that does network request (using cohttp), but these requests can fail. So to handle errors my function output something of type:
<discocaml> <jo.blade> ```ocaml
<discocaml> <jo.blade> type 'a request_finished =
<discocaml> <jo.blade> [ `Ok of 'a (** Successfuly run operation with result *)
<discocaml> <jo.blade> | `Need_Authentication of Uri.t (** Authentication failed when run request *)
<discocaml> <jo.blade> | `Error of Uri.t
<discocaml> <jo.blade> (** There was an error with the operation
<discocaml> <jo.blade> but we do not precise the type of error *)
<discocaml> <jo.blade> ]
<discocaml> <jo.blade> (** A type to get status of a finished request *)
<discocaml> <jo.blade>
<discocaml> <jo.blade> (** not the actual function signature but an example *)
<discocaml> <jo.blade> val do_request : unit -> 'a request_finished
<discocaml> <jo.blade> ```
<discocaml> <jo.blade>
<discocaml> <jo.blade> I want to implement some caching or memoization (I don't know if the concept memoization apply here ?) to save the output of "do_request" for future calls only if the result was "`Ok \_". So I can't use the keyword Lazy as if I encounter an error I want to be able to retry later…
<discocaml> <jo.blade>
<discocaml> <jo.blade> So I don't know how to do this kind of thing correctly, or maybe if I do this in a completely different way…
<discocaml> <jo.blade> Hello, I need some help about how to do network caching in a purely functional manner. In my case I have a function that does network request (using cohttp), but these requests can fail. So to handle errors my function output something of type:
<discocaml> <jo.blade> ```ocaml
<discocaml> <jo.blade> type 'a request_finished =
<discocaml> <jo.blade> [ `Ok of 'a (** Successfuly run operation with result *)
<discocaml> <jo.blade> | `Need_Authentication of Uri.t (** Authentication failed when run request *)
<discocaml> <jo.blade> | `Error of Uri.t
<discocaml> <jo.blade> (** There was an error with the operation
<discocaml> <jo.blade> but we do not precise the type of error *)
<discocaml> <jo.blade> ]
<discocaml> <jo.blade> (** A type to get status of a finished request *)
<discocaml> <jo.blade>
<discocaml> <jo.blade> (** not the actual function signature but an example *)
<discocaml> <jo.blade> val do_request : Uri.t -> 'a request_finished
<discocaml> <jo.blade> ```
<discocaml> <jo.blade>
<discocaml> <jo.blade> I want to implement some caching or memoization (I don't know if the concept memoization apply here ?) to save the output of "do_request" for future calls only if the result was "`Ok \_". So I can't use the keyword Lazy as if I encounter an error I want to be able to retry later…
<discocaml> <jo.blade>
<discocaml> <jo.blade> So I don't know how to do this kind of thing correctly, or maybe if I do this in a completely different way…
Serpent7776 has joined #ocaml
YuGiOhJCJ has joined #ocaml
waleee has quit [Ping timeout: 252 seconds]
<discocaml> <gdiazlo> May be this can help you to design your function https://cs3110.github.io/textbook/chapters/ds/memoization.html
<discocaml> <jo.blade> Ok so if I understand well, I must use mutable/imperatives structures in my code. Isn't it against the functionnal phylosophy ?
olle has joined #ocaml
dawids has joined #ocaml
dawids has quit [Client Quit]
tomku has quit [Ping timeout: 248 seconds]
tomku has joined #ocaml
<discocaml> <otini_> The functional philosophy is that purely functional interfaces tend to compose better, but you can implement them however you wish
<discocaml> <otini_> and sometimes a mutable API can be the practical choice
<discocaml> <otini_> even languages that enforce pure interfaces, like Haskell, use mutation under the hood for performance, and it can have disadvantages
<discocaml> <otini_> like having a more complex performance behaviour, or leaking any kind of mutation into the interface types
<discocaml> <otini_> I would say it’s a spectrum to choose from
Tuplanolla has joined #ocaml
bartholin has joined #ocaml
<discocaml> <gdiazlo> I would say ocaml is practical in that sense. You can use an inmutable data structure, but for memoization you will create a new structure every time you want to add something. The overall design would be similar to what the example of the link i think.
<olle> Only thing missing is manual memory pools or stack allocs ^^
<olle> But Janestreet did that already or?
<discocaml> <jo.blade> In all cases, the function was not pure from the beginning (if I understand well) because the output depends of the network state and not only of the arguments ?
<discocaml> <gdiazlo> Does the function returns something different than a request_finished depending on the network state?
<discocaml> <jo.blade> no, should I ? I'm open to make modifications
<discocaml> <gdiazlo> I suppose if it always the same, then, the return of the function does not depend on the network state and it is pure?
Inline has joined #ocaml
YuGiOhJCJ has quit [Quit: YuGiOhJCJ]
lain` has quit [Remote host closed the connection]
lain` has joined #ocaml
lain` has quit [Remote host closed the connection]
lain` has joined #ocaml
Inline has quit [Ping timeout: 260 seconds]
Inline has joined #ocaml
neiluj has joined #ocaml
<neiluj> hey! if I have a function a top level main() function that returns a lwt promise that is executed, and that within it there is an Lwt.async call with a function that loops, will main terminate or hang?
<neiluj> and if main terminates, all the binded promises will terminate?
arya_elfren has quit [Remote host closed the connection]
seeg has quit [Remote host closed the connection]
ursa-major has quit [Remote host closed the connection]
whereiseveryone has quit [Remote host closed the connection]
jmcantrell has quit [Remote host closed the connection]
b0o has quit [Remote host closed the connection]
pluviaq has quit [Remote host closed the connection]
pmk has quit [Remote host closed the connection]
_alix has quit [Remote host closed the connection]
ggb has quit [Remote host closed the connection]
kuruczgy has quit [Remote host closed the connection]
immutable has quit [Remote host closed the connection]
philipwhite has quit [Remote host closed the connection]
richardhuxton has quit [Remote host closed the connection]
soni_ has quit [Remote host closed the connection]
ymherklotz has quit [Remote host closed the connection]
sleepydog has quit [Remote host closed the connection]
lane has quit [Remote host closed the connection]
patrick_ has quit [Remote host closed the connection]
rustyne has quit [Remote host closed the connection]
xvilka has quit [Remote host closed the connection]
Ankhers has quit [Remote host closed the connection]
philipwhite has joined #ocaml
pmk has joined #ocaml
lane has joined #ocaml
jmcantrell has joined #ocaml
patrick_ has joined #ocaml
ggb has joined #ocaml
soni_ has joined #ocaml
b0o has joined #ocaml
arya_elfren has joined #ocaml
whereiseveryone has joined #ocaml
kuruczgy has joined #ocaml
henrytill has joined #ocaml
pluviaq has joined #ocaml
Ankhers has joined #ocaml
rustyne has joined #ocaml
sleepydog has joined #ocaml
ursa-major has joined #ocaml
ymherklotz has joined #ocaml
richardhuxton has joined #ocaml
immutable has joined #ocaml
_alix has joined #ocaml
xvilka has joined #ocaml
seeg has joined #ocaml
lain` has quit [Remote host closed the connection]
<discocaml> <otini_> a question I’ve often asked myself
lain` has joined #ocaml
<discocaml> <otini_> According to https://gitlab.com/tezos/tezos/-/issues/812, `async` does register via side effects the promise and schedules it, so I expect the call to `Lwt.main_run` will not terminate while the promise passed to `async` hasn’t been fulfilled. But that’s an easily testable hypothesis
<neiluj> indeed, thanks for chiming in!
<neiluj> looks like it's the case
lain` has quit [Remote host closed the connection]
lain` has joined #ocaml
<discocaml> <otini_> okay, good to know
olle has quit [Ping timeout: 252 seconds]
Inline has quit [Quit: Leaving]
<discocaml> <jo.blade> About Lwt, is it possible to run `Lwt_main.run` multiple times in parallel or it will cause bugs ?
<reynir> I think maybe the documentation covers that
<discocaml> <jo.blade> My problem is: I want to write a fuse filesystem in ocaml using [ocamlfuse](https://github.com/astrada/ocamlfuse). But the way the module is coded I have to write callback functions that return `unit` and not `unit Lwt.t`. I don't have all the knowledge of Lwt so I couldn't find another way that doing this:
<discocaml> <jo.blade>
<discocaml> <jo.blade> ```ocaml
<companion_cube> will cause bugs
<discocaml> <jo.blade> let _ =
<discocaml> <jo.blade> Fuse.main Sys.argv
<discocaml> <jo.blade> {
<discocaml> <jo.blade> Fuse.default_operations with
<discocaml> <jo.blade> getattr = do_getattr;
<discocaml> <jo.blade> readdir = (fun a b -> Lwt_main.run (do_readdir a b));
<discocaml> <jo.blade> }
<discocaml> <jo.blade> ```
<discocaml> <jo.blade>
<discocaml> <jo.blade> But in fact ocamlfuse github page states that readdir can be called in multiple threads so I think that explains some bug I encounter…
<companion_cube> lwt is full of non-thread-safe global state
<discocaml> <jo.blade> Hum… It was what I thought… unfortunately. But I couldn't find a way to make the threads connect to existing Lwt context or anything like this…
<discocaml> <jo.blade> I don't know how threads work in ocaml but maybe can I make a sort of inter-process pipe between the threads created by ocamlfuse and on main Lwt thread that will run every actual functions ?
<discocaml> <jo.blade> (btw, I see that you are not using discord, I didn't know this server was bridged with others platform, which ones are supported ? irc, matrix, xmpp ?)
<discocaml> <Kali> irc
<discocaml> <Kali> as noted by the channel description
<discocaml> <darrenldl> @jo.blade are you stuck in ocaml 4? if not then i think its time to try ocaml 5 concurrency libs, e.g. eio, miou, riot
<discocaml> <sim642> I haven't used ocamlfuse, but I suspect combining it with any additional concurrency will be quite problematic. Whoever is calling the callbacks you provide probably has all the control over how it wants to call them
neiluj has quit [Read error: Connection reset by peer]
neiluj has joined #ocaml
neiluj has quit [Read error: Connection reset by peer]
neiluj has joined #ocaml
<neiluj> okay off topic but I notice that I'm spending a heck of a lot of time rebasing when working on a codebase moving at a fast pace
<neiluj> wouldn't it be nice if an AI tool could do that for me?
lain` has quit [Remote host closed the connection]
lain` has joined #ocaml
<discocaml> <jo.blade> Ok finally I think I found a solution with `Lwt_preemptive.run_in_main `
<discocaml> <getzapped.> is using modules for dynamic dispatch to simulate something like dyn in rust idiomatic? something like this
<discocaml> <getzapped.> ```ocaml
<discocaml> <getzapped.> module type Show = sig
<discocaml> <getzapped.> type t
<discocaml> <getzapped.> val show : t -> string
<discocaml> <getzapped.> val instance : t
<discocaml> <getzapped.> end
<discocaml> <getzapped.>
<discocaml> <getzapped.> let print_list (lst : (module Show) list) =
<discocaml> <getzapped.> match lst with
<discocaml> <getzapped.> | [] -> ()
<discocaml> <getzapped.> | (module X) :: xs -> begin
<discocaml> <getzapped.> print_endline @@ X.show X.instance;
<discocaml> <getzapped.> print_list xs
<discocaml> <getzapped.> end
<discocaml> <getzapped.> ```
<discocaml> <getzapped.> is using modules for dynamic dispatch to simulate something like dyn in rust idiomatic ocaml? something like this
<discocaml> <getzapped.> ```ocaml
<discocaml> <getzapped.> module type Show = sig
<discocaml> <getzapped.> type t
<discocaml> <getzapped.> val show : t -> string
<discocaml> <getzapped.> val instance : t
<discocaml> <getzapped.> end
<discocaml> <getzapped.>
<discocaml> <getzapped.> let print_list (lst : (module Show) list) =
<discocaml> <getzapped.> match lst with
<discocaml> <getzapped.> | [] -> ()
<discocaml> <getzapped.> | (module X) :: xs -> begin
<discocaml> <getzapped.> print_endline @@ X.show X.instance;
<discocaml> <getzapped.> print_list xs
<discocaml> <getzapped.> end
<discocaml> <getzapped.> ```
<discocaml> <dx3mod> `Base` has abstractions for "idiomatically" writing such things
<discocaml> <dx3mod> ```ocaml
<discocaml> <dx3mod> let max (type t) (module C : Comparable.S with type t = t) =
<discocaml> <dx3mod> List.reduce ~f:(fun max_val x -> if C.(max_val < x) then x else max_val)
<discocaml> <dx3mod> ```
<discocaml> <dx3mod> `Base` has abstractions for "idiomatically" writing such things. Example:
<discocaml> <dx3mod> ```ocaml
<discocaml> <dx3mod> let max (type t) (module C : Comparable.S with type t = t) =
<discocaml> <dx3mod> List.reduce ~f:(fun max_val x -> if C.(max_val < x) then x else max_val)
<discocaml> <dx3mod> ```
<discocaml> <getzapped.> thats not quite the same though, as the whole list is of the same type, no?
TCZ has joined #ocaml
<discocaml> <getzapped.> my print_list could take a list with a mix of integers, lists, floats, and whatever else and print them all the same
Inline has joined #ocaml
<discocaml> <Kali> try to avoid editing (or posting) large code blocks since newlines have to be split into messages and edits resend the message, on the irc side
<discocaml> <Kali> in this channel
<discocaml> <dx3mod> Do you want heterogeneous lists?
<discocaml> <getzapped.> my bad didnt know
<discocaml> <Kali> #beginners and #advanced-help are suitable for this instead
<discocaml> <getzapped.> is the block the problem here or should it not be discussed in general
<discocaml> <Kali> the block was the problem, though i guess if you don't post more then you can just keep talking here
<discocaml> <Kali> more blocks, that is
<discocaml> <getzapped.> yeah thats one of the uses, im following the ray tracing in one weekend in ocaml and the c++ they used made a hittable class, and a hittable list class which is a vector of pointers to hittable objects, and the hittable list is a hittable object itself
<discocaml> <getzapped.> so i came up with something like the above code, passing around modules of a hittable signature, which includes a val obj : t, instead of a list of a single type of object
<neiluj> hey! if I have a let* res = Lwt.pick [connection_promise; timeout_promise], how can in the case res = Timeout try to check if connection_promise has resolved before it gets cancelled?
neiluj has quit [Ping timeout: 248 seconds]
TCZ has quit []
Serpent7776 has quit [Ping timeout: 260 seconds]
Inline has quit [Quit: Leaving]
Anarchos has joined #ocaml
neiluj has joined #ocaml
Anarchos has quit [Quit: Vision[]: i've been blurred!]
mbuf has quit [Quit: Leaving]
Inline has joined #ocaml
TCZ has joined #ocaml
Anarchos has joined #ocaml
<Anarchos> dh` i use my dragon book, but still can't find how to reduce a conflict due to a special case.
neiluj has quit [Ping timeout: 248 seconds]
olle has joined #ocaml
neiluj has joined #ocaml
olle_ has joined #ocaml
TCZ has quit []
pi3ce has quit [Quit: https://quassel-irc.org - Chat comfortably. Anywhere.]
<discocaml> <polytypic> I only read this channel occasionally. Yes, Picos is definitely still under construction. Please ask questions / open issues on Picos repo, Picos discord, or the #concurrency channel (which I do currently follow).
olle_ has quit [Ping timeout: 260 seconds]
olle has quit [Ping timeout: 260 seconds]
neiluj has quit [Read error: Connection reset by peer]
TCZ has joined #ocaml
Inline has quit [Ping timeout: 244 seconds]
bartholin has quit [Quit: Leaving]
Anarchos has quit [Quit: Vision[]: i've been blurred!]
neiluj has joined #ocaml
neiluj has quit [Read error: Connection reset by peer]
<discocaml> <ada2k> what i was doing was outside the scope of picos anyway
<discocaml> <ada2k> i was essentially trying to on-demand spawn a loop at the creation of a domain, whilst respecting structured concurrency to run on miou. such a thing is afaik impossible without cooperation either from the user or scheduler
TCZ has quit []