companion_cube changed the topic of #ocaml to: Discussion about the OCaml programming language | http://www.ocaml.org | OCaml 4.14.0 released: https://ocaml.org/releases/4.14.0.html | Try OCaml in your browser: https://try.ocamlpro.com | Public channel logs at https://libera.irclog.whitequark.org/ocaml/
vicfred has quit [Quit: Leaving]
CalimeroTeknik has quit [Ping timeout: 256 seconds]
omni_ has joined #ocaml
quernd8 has joined #ocaml
ralu1 has joined #ocaml
omni has quit [Read error: Connection reset by peer]
ebb has quit [Remote host closed the connection]
SquidDev1 has joined #ocaml
ralu has quit [Ping timeout: 256 seconds]
SquidDev has quit [Ping timeout: 256 seconds]
SquidDev1 is now known as SquidDev
ralu1 is now known as ralu
quernd has quit [Ping timeout: 256 seconds]
quernd8 is now known as quernd
rgrinberg has joined #ocaml
ebb has joined #ocaml
mal`` has quit [Ping timeout: 256 seconds]
hannes__ has joined #ocaml
daimrod2 has quit [Ping timeout: 256 seconds]
theblatte has quit [Ping timeout: 256 seconds]
theblatte has joined #ocaml
tomku has quit [Ping timeout: 256 seconds]
hannes has quit [Ping timeout: 256 seconds]
Ekho has quit [Ping timeout: 256 seconds]
mal`` has joined #ocaml
Tuplanolla has quit [Quit: Leaving.]
tomku has joined #ocaml
Ekho has joined #ocaml
CalimeroTeknik has joined #ocaml
daimrod2 has joined #ocaml
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
rgrinberg has joined #ocaml
mbuf has joined #ocaml
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
bronsen has quit [Ping timeout: 252 seconds]
kaph has quit [Ping timeout: 260 seconds]
dextaa_54 has joined #ocaml
towel_ has quit [Ping timeout: 256 seconds]
towel has joined #ocaml
dextaa_5 has quit [Ping timeout: 256 seconds]
dextaa_54 is now known as dextaa_5
grobe0ba_ has joined #ocaml
grobe0ba has quit [Ping timeout: 256 seconds]
grobe0ba_ is now known as grobe0ba
rgrinberg has joined #ocaml
terrorjack has quit [Quit: The Lounge - https://thelounge.chat]
terrorjack has joined #ocaml
bobo has joined #ocaml
spip has quit [Ping timeout: 245 seconds]
waleee has quit [Ping timeout: 245 seconds]
gravicappa has joined #ocaml
gravicappa has quit [Ping timeout: 260 seconds]
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
zebrag has quit [Read error: Connection reset by peer]
gravicappa has joined #ocaml
mro has joined #ocaml
mro has quit [Remote host closed the connection]
mro has joined #ocaml
gravicappa has quit [Ping timeout: 268 seconds]
epony has quit [Quit: QUIT]
kaph has joined #ocaml
random-jellyfish has joined #ocaml
olle has joined #ocaml
dextaa_5 has quit [Remote host closed the connection]
epony has joined #ocaml
dextaa_54 has joined #ocaml
CalimeroTeknik has quit [Changing host]
CalimeroTeknik has joined #ocaml
perrierjouet has quit [Ping timeout: 260 seconds]
<ns12> Hello, if I find myself occasionally struggling with the type system, is there a book I can read to learn more about the type system?
<ns12> I am thinking of reading "Types and Programming Languages" by Benjamin C. Pierce, but I don't know if that would help.
<d_bot> <orbitz> What sort of issues do you run into?
<ns12> I write programs that are not correctly typed ...
<d_bot> <orbitz> I figured that part out
<ns12> because I don't know the limitations of the type system.
<d_bot> <orbitz> Is there a pattern in the issues you run into?
<ns12> Hard to say ...
<ns12> I guess I just want to learn the type system so that I can design APIs in my head without encountering type errors when I actually implement them.
<d_bot> <orbitz> I don't know of a book or any resource other than just trying to implement things
<d_bot> <orbitz> But getting errors from the type system isn't bad, not understanding how to resolve the errors is an issue
<ns12> I use too much Lisp, and some Lisp-like ways of expressing things is impossible in OCaml.
<ns12> "not understanding how to resolve the errors is an issue" - That is my issue, unfortunately.
<d_bot> <orbitz> Practice practice practice
<ns12> Often, when implementing library functions in OCaml, there is a non-type-safe way to do it and a type-safe way. But designing the type-safe implementation seems to require some understanding of the type system ...
<octachron> "Types and Programming Languages" would be useful to learn how type system are designed, but it not necessarily a fast path in learning how to write correctly typed programs.
<ns12> For example, https://github.com/anuragsoni/routes (a type-safe URL router). I actually have no idea how the API is implemented. I have tried for a few days now to make a clean room implementation.
<d_bot> <orbitz> Something like that is probably using some more advanced concepts
<ns12> octachron: Is that the slow way? I don't mind slow methods.
<d_bot> <orbitz> I implemented a type safe router by studying other ones and then just building it up slowly and asking qusetiosn
<octachron> That is a GADT-heavy library.
mro has quit [Remote host closed the connection]
<octachron> That's the the slow way, but also one that doesn't preclude practice. Typically, GADTs are not-that-complicated from the type system perspective, but they require a copious amount of practice before become intuitive
<ns12> "Something like that is probably using some more advanced concepts" - What are those "advanced concepts" and how do I learn them>
<ns12> s/>/?/
<d_bot> <orbitz> Yeah. I find GADTs really fascinating in that the actual change from an ADT is relatively minor, but the consequences are astounding
<d_bot> <orbitz> ns12: for example, GADTs
<octachron> And yes, GADTs do become intuitive at some point. To such way, that an important step in learning GADTs is to relearn "how to not use GADTs".
olle has quit [Quit: leaving]
olle has joined #ocaml
kaph has quit [Ping timeout: 246 seconds]
<ns12> How do I learn that?
<d_bot> <orbitz> Practice
<ns12> Is practice alone enough to fully appreciate these kinds of things?
<ns12> octachron: "That is a GADT-heavy library." - Thank you for the tip.
<d_bot> <orbitz> Depends on how good of a practicer you are
<octachron> Some canonical examples of GADTs: a shallow embedded interpreter for a small DSL, lists with statistically known lengths, heterogeneous lists
<d_bot> <orbitz> ns12: https://www.cl.cam.ac.uk/teaching/1415/L28/gadts.pdf -- I found pretty helpful
<octachron> writing your own version of Printf is a good exercice (which is also an example of typed interpreter for a small DSL)
<ns12> octachron: Is Printf implemented using GADTs? Can it be implemented in other ways?
<ns12> orbitz: What book does that chapter come from?
<octachron> Printf is implemented with GADTs and a bit of syntactic magic to have format strings look lile strings
bartholin has joined #ocaml
mro has joined #ocaml
<octachron> It cannot really be implemented with an user-friendly interface without GADTs.
<d_bot> <orbitz> Pre-GADTs is was mostly a bunch of compiler-specific code, right?
<ns12> octachron: "syntactic magic" - Does that mean that I cannot implement an interface exactly like Printf.printf ?
<d_bot> <orbitz> ns12: Might be interesting to you: https://blog.tail.moe/2021/01/13/format6.html
<octachron> Not exactly, but it is still possible to have a readable format GADTs.
<octachron> For instance "Hello %s" is essentially syntactic sugar for String_literal ("Hello ", String (No_padding, End_of_format))
mro has quit [Remote host closed the connection]
mro has joined #ocaml
<ns12> So, it's not possible for me to implement `myprintf "Name: %s Age: %d" "Alice" 123` ?
<octachron> Yes, but you can implement `myprintf [Lit "Name: "; String; Lit "Age: "; Int] "Alice" 123`
<ns12> octachron: Is the Printf.printf function handled specially by OCaml?
<octachron> and then use a ppx to get to `myprintf {%fmt|Name: %s Age: %d|} "Alice" 123`
<octachron> The `Printf.printf` is an ordinary function. It is "Name: %s Age: %d" which is not a string because its type is _ format6
<octachron> Ah, slight correction, you can reuse the Format GADTs to really immplement `myprintf "Name: %s Age: %d" "Alice" 123`
<octachron> It is just that Format/Printf cover a large API which is a bit unwieldy to reuse in a learning project.
<octachron> (And there is the issue of the "%{...}" specifier)
gravicappa has joined #ocaml
<ns12> octachron: So, it's possible to create `myprintf [Lit "Name: "; String; Lit "Age: "; Int]` which has type `string -> int -> 'a` in OCaml by using GADTs? Is it possible to implement such a thing without GADTs?
<d_bot> <orbitz> Depending on the API you can accomplish some similar things with closures
<d_bot> <orbitz> The API would probably not look like that, though (lists)
<octachron> Also note that this is not a stdlib's list but a heterogeneous list.
<octachron> Also the type would not be "string -> int -> 'a" but "string -> int -> t" for some t.
<octachron> But yes, it is otherwise possible with GADTs, or with some complex use of closures, but not with simple ADTs.
<ns12> orbitz: "What sort of issues do you run into?" - One of them is how to define a function `myprintf` that when used like `myprintf [Lit "Name: "; String; Lit "Age: "; Int]` results in something with type `string -> int -> t`.
<ns12> I guess GADT is the answer, which I have not learned about before.
<d_bot> <orbitz> ns12: IME, writing such functions is fairly uncommon.
<ns12> octachron: "But yes, it is otherwise possible with GADTs, or with some complex use of closures ... " - Really? It's possible with closures?
random-jellyfish has quit [Quit: Client closed]
<ns12> Hmm ... I guess something like this could work:
<ns12> let lit s = fun k -> k
<ns12> let (/+) a b = fun k -> a (b k)
<ns12> let int = fun k (i : int) -> k
<ns12> let str = fun k (s : string) -> k
<ns12> Then, `lit "Name: " /+ str /+ lit "Age: " /+ int` will have type `t -> string -> int -> t`.
mro has quit [Remote host closed the connection]
mro has joined #ocaml
mro has quit [Remote host closed the connection]
mro has joined #ocaml
perrierjouet has joined #ocaml
Haudegen has joined #ocaml
bartholin has quit [Ping timeout: 248 seconds]
bartholin has joined #ocaml
dextaa_54 has quit [Read error: Connection reset by peer]
dextaa_54 has joined #ocaml
kaph has joined #ocaml
mro has quit [Ping timeout: 246 seconds]
hannes__ is now known as hannes
bartholin has quit [Ping timeout: 246 seconds]
bartholin has joined #ocaml
mro has joined #ocaml
perrierjouet has quit [Ping timeout: 272 seconds]
mro has quit [Remote host closed the connection]
mro has joined #ocaml
mro has quit [Ping timeout: 260 seconds]
perrierjouet has joined #ocaml
kaph has quit [Ping timeout: 246 seconds]
mro has joined #ocaml
kaph has joined #ocaml
Anarchos has joined #ocaml
bartholin has quit [Ping timeout: 240 seconds]
mro has quit [Remote host closed the connection]
bartholin has joined #ocaml
mro has joined #ocaml
mro has quit [Remote host closed the connection]
mro has joined #ocaml
bartholin has quit [Ping timeout: 272 seconds]
rgrinberg has joined #ocaml
bronsen has joined #ocaml
bartholin has joined #ocaml
<d_bot> <ec> Is there a codemod library, something like `jscodeshift`, to simplify and speed up writing small codemods for OCaml source-code?
<d_bot> <ec>
<d_bot> <ec> in particular, the fact it depends on a parser/lexer that intentionally *do not* throw away information, in the hopes of reconstituting the original code with the least-possible changes, seems like something I've not come across in the ML ecosystems …
spip has joined #ocaml
bobo has quit [Ping timeout: 248 seconds]
dextaa_54 has quit [Read error: Connection reset by peer]
dextaa_54 has joined #ocaml
<d_bot> <VPhantom> I never dealt with "codemods" (had to look up the word just now) but in my experience with OCaml the type system is all I have needed when refactoring. I haven't maintained large code bases yet though.
<companion_cube> oh hey @VPhantom
<d_bot> <VPhantom> Bonjour! 😃
<d_bot> <bikachuu> Hello
neilthereildeil has joined #ocaml
<neilthereildeil> hey guys
<neilthereildeil> what does this code do?
<neilthereildeil> List.iter (add_event (fun x -> x.read <- true)) in_fds;
<neilthereildeil> can someone please break it down into peices?
<neilthereildeil> i think this is an anonymous function: fun x -> x.read <- true
<neilthereildeil> but i dunno what it does
<d_bot> <VPhantom> Useful reference: <https://ocaml.org/api/List.html#1_Iterators>
<d_bot> <bikachuu> x is a record that has a mutable field `read : bool`, and this anonymous function sets that field to `true`
zebrag has joined #ocaml
<d_bot> <VPhantom> I guess `add_event` takes more than one argument and is curried here.
<d_bot> <ec> A big part of the point is to have the changes stored, historically — it's also really helpful to have a branch be not just a set of changes and a *human* ability to rebase those changes on top of others' work when they're ready … but to also have the ability to *mechanically* apply those changes to any rebasing branches.
<d_bot> <VPhantom> Hence why it's higher-level than a mere commit. I see.
<d_bot> <ec> idk if i explained that well, not very awake. tl;dr "human following type-system" + "lots of contributors" == "that human having to make those changes all over again every couple of days/weeks";
<d_bot> <ec> but "machine making changes" + "lots of contributors" == "machine re-making those changes for each contributor"
<d_bot> <ec> it also has a couple nice side-effects w.r.t. debugging down the road, and w.r.t. bikeshedding — it's a bit like an autoformatter in that respect.
<neilthereildeil> so do we evaluate the code from the most nested expression, outwards?
<neilthereildeil> in this case, do we read the "fun x -> x.read <- true" first?
<d_bot> <ec> it's eager evaluation, so (mostly) yes
<neilthereildeil> so frm the documentation, it looks like it executes that function on each element of the list, right?
<d_bot> <ec> if you're unfamiliar with currying, it's important to note that there's effectively a second anonymous function in there as well
<d_bot> <ec> List.iter (fun y -> add_event (fun x -> x.read <- true) y) in_fds
<d_bot> <ec> this is because (I'm assuming, from looking at the code) `add_event` must be partially applied — it needs more arguments than just that first `fun x ...` lambda.
<d_bot> <VPhantom> Exactly.
<d_bot> <Ambika E.> I'm trying to organize a dune library in a way such that I have a top-level module, call it `Node`, with some top-level values, e.g. `Node.create`, but I want it to have sub-modules as well, e.g. `Node.Server` and I want those modules to exist in their own files. Is this possible? I know I can do this in one file quite easily, but I'm not sure how splitting it into several works if i want those top-level values
bartholin has quit [Quit: Leaving]
<d_bot> <ec> Can explain in more detail if the docs don't cover it, feel free to ask! (=
<d_bot> <octachron> Yes, if you have a library called `lib` and a module `Lib`, `dune` will consider that the module `Lib` is the main entry point of the library. Then, you just have to re-export the other modules in the library with `Module Sub = Sub`.
<neilthereildeil> i just read about currying
<neilthereildeil> so it seems the function format myFunc a b c is "curryed"
<d_bot> <octachron> @ec : `(wrapped false)` is not that much of a good advice because it exposes the non-qualified names `Sub` and thus it increases the risk of name collisions.
<neilthereildeil> are you only thinking its curried because its partially applied?
<d_bot> <ec> Oh, I didn't know about the matching-name-single-export functionality
<d_bot> <ec> I thought you'd just end up with `Lib.Lib.create`, which is what he's trying to avoid. Cool1
<d_bot> <Ambika E.> wrapped false is not exactly what i want
<d_bot> <Ambika E.> that would expose _every_ module in my library directly
<neilthereildeil> also how do you knoiw the function is partially applied?
mro has quit [Remote host closed the connection]
<d_bot> <Ambika E.> it's partially applied because the second argument to `List.iter` is a function, meaning that the application of `add_event` returned a function rather than a non-function value. This implies partial application to some extent.
<d_bot> <ec> `List.iter` takes a function as its first argument; and based on the name `add_event`, I'm guessing that second clause doesn't return a function when it's fully-applied. Just a guess, though. ¯\_(ツ)_/¯
<d_bot> <Ambika E.> first argument, my bad
<d_bot> <Ambika E.> the structure i want to mimic with dune is something like
<d_bot> <Ambika E.>
<d_bot> <Ambika E.> node.ml
<d_bot> <Ambika E.> ```ocaml
<d_bot> <Ambika E.> let create ... = ...
<d_bot> <Ambika E.>
<d_bot> <Ambika E.> module Server = struct
<d_bot> <Ambika E.> let init ... = ...
<d_bot> <Ambika E.> ...
<d_bot> <Ambika E.> end
<d_bot> <Ambika E.> ```
<d_bot> <Ambika E.>
<d_bot> <Ambika E.> such that the consumer of this library could run `Node.create` or `Node.Server.init`.
<neilthereildeil> heres the signature of iterator:
<neilthereildeil> val iter : ('a -> unit) -> 'a list -> unit
<d_bot> <Ambika E.> `wrapped false` just means that the consumer can directly run `Node.create` or `Server.init`
<d_bot> <Ambika E.> not necessarily what i'm looking for
<neilthereildeil> the () means that the first argument is a function, right?
<d_bot> <Ambika E.> yeah, that's what it's signifying
<neilthereildeil> in
<neilthereildeil> List.iter (add_event (fun x -> x.read <- true)) in_fds;
<neilthereildeil> it looks like in_fds is the second argument
<neilthereildeil> right?
<d_bot> <Ambika E.> yes
<neilthereildeil> so then how is it partially applied?
<neilthereildeil> i see it as List.iter () in_fds
<neilthereildeil> where the () is the function
<d_bot> <ec> you'll have to ask @octachron about it — but it sounds like that's only possible if the *library* is also named `node`? hrm.
<d_bot> <Ambika E.> even if it were, i don't think my problem is solved, it doesn't seem like you can expose top-level values with dune libraries that way
<d_bot> <Ambika E.> i basically want something like python's `__init__.py`
<d_bot> <octachron> You can add any toplevel values that you want in `node.ml`.
<d_bot> <Ambika E.> really?
<neilthereildeil> also, what does "<- true" do?
<d_bot> <Ambika E.> that's assignment to a mutable record field
<d_bot> <octachron> Yes, the only constraint is that you also need to export the submodules of the library
<d_bot> <ec> `<-` is OCaml's weird-ass syntax for "mutating assignment." Depending on the language you're coming from, it's probably best read something like `=`. :P
<d_bot> <Ambika E.> i see, i'll give this a try, i appreciate it a lot
<d_bot> <ec> for instance, JavaScript `an_object.some_key = 123` becomes OCaml's `a_record.some_mutable_key <- 123`.
<d_bot> <Ambika E.> check the signature of add_event
<neilthereildeil> heres the code: https://paste.debian.net/1236903/
<d_bot> <Ambika E.> yeah, see, add_event takes 2 arguments, not one
<neilthereildeil> add_event looks like it returns e
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<d_bot> <Ambika E.> the fact that you only pass it one argument means it's being applied partially
<neilthereildeil> wow thats confusing
<d_bot> <Ambika E.> not once you get used to it
<d_bot> <Ambika E.> it's a common pattern
<neilthereildeil> ok so add_event is partially applied
<neilthereildeil> because we dont pass enough parameters?
<d_bot> <ec> Partial application is super-important. If you're coming from a non-functional background, it's best to think of it as "every function *defaults* to returning another function, if you don't give it everything it needs."
<d_bot> <Ambika E.> yeah, you pass the first parameter, so the result is a function that's still waiting for the second param
<neilthereildeil> lol wow so its liike partially executed??
<d_bot> <ec> i.e. `let mult a b = a * b`, if you only give it `a`, becomes `let mult a = (fun b -> a * b)` automatically.
<d_bot> <Ambika E.> sure, except nothing actually runs
rgrinberg has joined #ocaml
<neilthereildeil> ohhh i get it
<d_bot> <Ambika E.> the function won't actually get called until it gets all its inputs
<d_bot> <Ambika E.> it kind of creates a half-filled shell of a function call
<neilthereildeil> wow cool
<d_bot> <Ambika E.> it is really cool
<d_bot> <ec> it's very helpful for all sorts of things.
<d_bot> <ec> 1. you can explicitly use that to create specialized, helper functions: `let triple = mult 3`
<neilthereildeil> so then when is add_event actually executed?
<neilthereildeil> when does it have enough params?
<d_bot> <Ambika E.> in the execution of List.iter
<d_bot> <ec> 2. And in situations like the above, you don't have to waste a bunch of space typing out a lambda; you can just pass it an unfinished function, as long as the "last" argument to the function is the operable item
<d_bot> <Ambika E.> List.iter plugs each file descriptor in `in_fds` into the partially applied function
<neilthereildeil> so is in_fds an argument to List.iter or add_event?
<d_bot> <Ambika E.> `in_fds` is a list of arguments to `add_event`, and thus it is an argument to `List.iter` 😎
<d_bot> <Ambika E.> that's how list iter works
<d_bot> <Ambika E.> it takes a function and a list of things you want to apply the function to
<d_bot> <Ambika E.> and it does just that
<d_bot> <Ambika E.> it's like a specialized for loop condensed into one line
<neilthereildeil> damn
<neilthereildeil> very dense
<neilthereildeil> so is in_fds passed to List.iter first, and List.iter passes it as a parameter to add_event interally?
<d_bot> <Ambika E.> let me show you a simpler example of how List.iter is used
<neilthereildeil> thx
<d_bot> <ec> It might help to break that function down a tiny bit: https://gist.github.com/ELLIOTTCABLE/d52790220e22dcd83b6ec147d5d0bf79
<d_bot> <ec> er, @help-ee-dude
<d_bot> <Ambika E.> ```ocaml
<d_bot> <Ambika E.> let numbers = [1; 2; 3; 4; 5; 6 ; 7; 8; 9; 10]
<d_bot> <Ambika E.>
<d_bot> <Ambika E.> let multiply a b = a * b
<d_bot> <Ambika E.>
<d_bot> <Ambika E.> (* Print out every multiple of 2 from 1 to 10 *)
<d_bot> <Ambika E.> List.iter (fun x > print_int (multiply 2 x)) numbers
<d_bot> <Ambika E.> ```
<d_bot> <Ambika E.>
<d_bot> <Ambika E.> there's no partial application here, but you can kind of see that the argument to `List.iter` is obviously not the argument to `multiply`
<d_bot> <ec> I also added a JavaScript equivalent (if you let me know what language you're most familiar with, neil, I can possibly use that instead?)
mbuf has quit [Quit: Leaving]
<neilthereildeil> ec: ok, it took like 8 minutes but i understand ur code
<d_bot> <ec> ❤️
<neilthereildeil> thax so much. im a C guy, so i think in a totally different
<neilthereildeil> way
<d_bot> <ec> ahhahhah, oof, that's a *big* transition. good luck!
<d_bot> <ec> don't be afraid of grabbing any code you are confused by, dropping it into `utop` or a text-editor with LSP support, and starting to add a bunch of explicit anonymous-functions everywhere. if you screw something up, the type-system will tell you. it's a good stretch if you're not familiar with partial-application and such.
<neilthereildeil> Ambika: thanks for the code
<d_bot> <ec> I'm surprised this Discord doesn't have a #menhir or #parsing channel for Menhir / Sedlex stuff
<neilthereildeil> ec: im just trynna fix 1 bug, and im (re)learning ocaml for this! haha
<neilthereildeil> also, that anonymous function:
<neilthereildeil> fun x -> x.read <- true
<neilthereildeil> unconditionally sets "read" field to true, correct? what if no read field exists in the object?
<d_bot> <ec> impossible, all constrained by the type-system. `x` has a very specific type. I really hope you're reading this inside an editor with `ocaml-lsp` or similar, by the way — I'm a pretty deft hand with OCaml, and I'd be *totally* incompetent without a 'what's the type of this value' hotkey :P
<octachron> Records are nominal and statistically typed. The field is guaranteed to exist in the record.
<d_bot> <ec> even just for fixing one bug, it's worth quickly installing whatever editor-plugin is relevant.
<neilthereildeil> im using VIsualStudio code
<d_bot> <ec> I just set this up yesterday! It's nice and quick. https://github.com/ocamllabs/vscode-ocaml-platform
<neilthereildeil> the type of x is not explicitly listed in the code
<d_bot> <ec> yep, we very very rarely type out types manually — mostly only as a form of comments/documentation, honestly. OCaml is really heavy on the type-inferrence.
<d_bot> <ec> Was just about to suggest we move this to #beginners, but ah. you're over the IRC bridge.
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
<neilthereildeil> also, one thing i didnt understand in the compact form:
<neilthereildeil> List.iter (add_event (fun x -> x.read <- true)) in_fds;
<neilthereildeil> is in_fds first passed to iter, which then passes it to add_event?
<d_bot> <ec> half-yes — `in_fds` is indeed an argument to `iter`, but only *one* `in_fd` is passed to `add_event`.
<d_bot> <ec> that being the entire purpose of `iter`
<neilthereildeil> ok cool. i just wanted to make sure i understood the order of parameter passing
<neilthereildeil> also, since fun unconditionally sets x.read=true, where are we guaranteed that x has a read field?
<d_bot> <ec> by that code existing, basically.
<d_bot> <NULL> compiling*
<d_bot> <ec> the compiler will infer from that code _that_ `x` is a value with a record-type that looks like `{ mut read: bool; … }`, and then it'll explode if the values in `in_fds` don't match that expectation.
<neilthereildeil> okay compile time. thats better than python where the server could be running for 2 days and then throws an error that an attribute doesnt exist!
<d_bot> <NULL> OCaml is pretty much as statically typed as you get
Anarchos has quit [Quit: Vision[]: i've been blurred!]
rgrinberg has joined #ocaml
szkl has joined #ocaml
<olle> Hmmm
<olle> No refined typed tho :))
<olle> Or dependent, etc etc
<olle> Or even kinds?
<d_bot> <NULL> I didn't say it has the most types
<d_bot> <NULL> had*
<d_bot> <ec> i may be being crotchety, but … in real-world development, most of OCaml's *existing* complicated type-features don't really get used much. Honestly, it's often "best avoided".
<d_bot> <ec> Not saying gaining those features would be a net loss, but I *am* saying that not having them isn't a significant drawback, at least for pragmatic production codebases. :P
<d_bot> <ec> "Good code can be understood by an intern; better code is that-but-less-of-it; and the best code is none at all." and all that
<d_bot> <octachron> I don't completely agree, GADTs are not completely trivial, and tend to spread to code base pretty fast.
dextaa_54 has quit [Read error: Connection reset by peer]
dextaa_54 has joined #ocaml
<d_bot> <Ambika E.> any idea what's going on here?
<companion_cube> ah, well, Mutex.t doens't have type arguments
<companion_cube> sadly
<d_bot> <Ambika E.> but clearly it does? no?
<companion_cube> ah wait, you may be using a library that hides it
<companion_cube> and esy doesn't pick it up
<d_bot> <Ambika E.> it is exposed in the mli
<d_bot> <Ambika E.> to what extent more could it be hidden?
<companion_cube> I mean.
<companion_cube> you may be using a library that defines `'a Mutex.t`
<companion_cube> instead of the standard Mutex.t which has no argument
<companion_cube> and esy doesn't know about that library maybe
<d_bot> <Ambika E.> oh wow
<d_bot> <Ambika E.> didn't realize OCaml had a built-in Mutex module
<companion_cube> it does, it's in the threads library :)
<d_bot> <Ambika E.> interesting
<companion_cube> https://ocaml.org/api/Mutex.html even
Tuplanolla has joined #ocaml
<neilthereildeil> what does this code do? https://paste.debian.net/1236908/
<d_bot> <NULL> A triple filter in one go
<neilthereildeil> what is it applying fold_right to?
<neilthereildeil> the r and then the a?
<d_bot> <NULL> It's folding over a with base value r
<d_bot> <ec> https://ocaml.org/api/Array.html#VALfold_right, if you didn't already find that.
<neilthereildeil> that signature definition language is just as confusing as the code itself, so i looked elsewhere! LOL
* d_bot <ec> laughs
<d_bot> <ec> I can relate, I've struggled with Haskell's syntax for *years*. Unfortunately it's used absolutely everywhere in fp and strong-typing spaces.
<d_bot> <ec> The important part in the definition is the `'blah` type-variables, with a single-quote before them. Any two sharing a letter are the same type.
<d_bot> <ec> I personally cannot fathom why so many in the FP space (including other OCamleers) struggle to type more than a single letter for typevar names. If it helps:
<d_bot> <ec>
<d_bot> <ec> ```ocaml
<d_bot> <ec> val fold_right : ('thing -> 'result -> 'result) -> 'thing array -> 'result -> 'result
<d_bot> <ec> ```
<d_bot> <octachron> Partially because `'result` and `'thing` are not much more informative than `'a` and `'b`:
<d_bot> <octachron> val fold_right: ('elt -> 'acc -> 'acc) -> 'elt array -> 'acc -> 'acc
<d_bot> <octachron> is a bit better.
mro has joined #ocaml
mro has quit [Remote host closed the connection]
mro has joined #ocaml
vicfred has joined #ocaml
<neilthereildeil> so whats the "operation" thats being used to fold?
mro has quit [Remote host closed the connection]
mro has joined #ocaml
<companion_cube> whatever you want it to be
<octachron> The first argument is a function that takes an array element ('elt) and an accumulator and returns the next accumulator
<neilthereildeil> i "want it to be" something i understand :(
<companion_cube> well, fold is a function to which you pass a function
<companion_cube> e.g. `fun l -> List.fold_left (+) 0 l` is summing over the list
<companion_cube> you, the caller, choose the operation
<neilthereildeil> what is  'acc -> 'acc?
<neilthereildeil> why are there 2 acc?
<octachron> You can think of it as a way to specify a for-loop over the array where each turn of the loop is computed as `state = f(array[i], state)`
<companion_cube> there's the one you pass as the initial value, and the one returned at the end
<neilthereildeil> val fold_right: ('elt -> 'acc -> 'acc) -> 'elt array -> 'acc -> 'acc
<neilthereildeil> both the function and the last 2 args are acc
<companion_cube> fun l -> fold_right (+) l 0
<neilthereildeil> what does that signify?
<companion_cube> 'acc is just a type
<neilthereildeil> so we know it takes a function because of the ()
<companion_cube> the type of the accumulator that is passed to the function, along with each element of the list
<neilthereildeil> right?
<neilthereildeil> can someone please break down step by step how to evaluate this?
<neilthereildeil> val fold_right: ('elt -> 'acc -> 'acc) -> 'elt array -> 'acc -> 'acc
<neilthereildeil> where do you start from?
<companion_cube> you mean to read the type?
<neilthereildeil> the function signature i think...
<companion_cube> same thing
<companion_cube> well, everything on the left of `-> ` is a function argument
<companion_cube> here: ('elt -> 'acc -> 'acc) is an argument
<companion_cube> 'elt array too
<companion_cube> and 'acc too
neilthereildeil has quit [Quit: Client closed]
<companion_cube> ahah fuck
neilthereildeil has joined #ocaml
<neilthereildeil> so ('elt -> 'acc -> 'acc) is the argument to fold_right?
<companion_cube> it's one of the arguments
<companion_cube> and it's itself a function
<neilthereildeil> im confused
<neilthereildeil> i thought all the arguments are inside the ()
<companion_cube> no :)
<neilthereildeil> so what does () mean here?
<companion_cube> it's used to delimit a type
<neilthereildeil> like a tuple?
<neilthereildeil> since theres 3?
<companion_cube> like in `a * (b + c)` it is used to delimit a sub-expression
<companion_cube> here it's used to delimit a type
<neilthereildeil> whats the type thats delimited here?
<companion_cube> 'elt -> 'acc -> 'acc
<neilthereildeil> looks like 3 types to me...
<companion_cube> I think you need to read about simpler types than that first
<companion_cube> no, it's a function type because of the ->
<companion_cube> `Array.set : 'a array -> int -> 'a -> unit` for example
<companion_cube> that's the function to set an array slot by its index
<neilthereildeil> ok, so if i have -> between types then its a function?
<d_bot> <NULL> The way you read these types is related to the currying we talked about above
<d_bot> <NULL> Here, `Array.set` takes 3 arguments: one array, an int, a value (with type 'a, the types of values on the array) and returns unit
<d_bot> <NULL> You can also see it as a function that takes an array and returns a function that then takes an int and returns a function that then takes a value and returns unit
<d_bot> <NULL> `'a array -> (int -> ('a -> unit))`
<d_bot> <NULL> Those types are equal
<d_bot> <NULL> Do you follow until now ?
waleee has joined #ocaml
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
neilthereildeil has quit [Quit: Client closed]
Nahra has joined #ocaml
<d_bot> <Continuation Calculus> hey
<d_bot> <Continuation Calculus> I have troubles understanding the error message in https://pastebin.com/E3NHLApY
<d_bot> <Continuation Calculus> finally understood: don't call a functor `A(...)` and then do `module rec A = A(...)` 😄
mro has quit [Read error: Connection reset by peer]
mro has joined #ocaml
<d_bot> <octachron> At the same time, I should really restore the error message for the non-functor case.
mro_ has joined #ocaml
Anarchos has joined #ocaml
jackhill is now known as KM4MBG
KM4MBG is now known as jackhill
mro has quit [Ping timeout: 268 seconds]
dextaa_54 has quit [Remote host closed the connection]
<d_bot> <Continuation Calculus> ah. what i wanted was doomed either way: recursive values are a pain in OCaml
Haudegen has quit [Quit: No Ping reply in 180 seconds.]
Haudegen has joined #ocaml
neilthereildeil has joined #ocaml
<neilthereildeil> hi is this the correct way to set a variable to -1?
<neilthereildeil> let period_ops_interval = -1. in
<Anarchos> neilthereildeil no, you just defined a constant. If you need a variable, you should do let period_ops_interval = ref (-1.)
<neilthereildeil> oops wrong question
<Anarchos> neilthereildeil «ref» are mutable values
<neilthereildeil> ok, this is supposed to be a constant
<Anarchos> you dereference them with "!"
<neilthereildeil> is what i pasted corect?
<Anarchos> yes it is for a constant
<neilthereildeil> k thx
<d_bot> <NULL> I think we should forget the original definition of variable and let it be any defined ident; add mutable if we want it to be
rgrinberg has joined #ocaml
neilthereildeil has quit [Quit: Client closed]
mro_ has quit [Remote host closed the connection]
mro has joined #ocaml
olle has quit [Ping timeout: 248 seconds]
<d_bot> <romachkuna> ```ocaml
<d_bot> <romachkuna> type student = {
<d_bot> <romachkuna> firstname : string;
<d_bot> <romachkuna> lastname : string;
<d_bot> <romachkuna> id : int;
<d_bot> <romachkuna> }
<d_bot> <romachkuna> ```
<d_bot> <romachkuna> how can i remove students with certain id's from students lsit?
<d_bot> <romachkuna> ```ocaml
<d_bot> <romachkuna> let rec remove_by_id id list = match list with
<d_bot> <romachkuna> | [] -> []
<d_bot> <romachkuna> | h::t -> if h.id = id then h :: remove_by_id id t else remove_by_id id t
<d_bot> <romachkuna> ``` tried something like this but its not working
gravicappa has quit [Ping timeout: 248 seconds]
<d_bot> <undu> The code removes the items from the list that do _not_ match the id
wingsorc has quit [Quit: Leaving]
motherfsck has quit [Quit: bye]
wingsorc has joined #ocaml
<Anarchos> romachkuna there must be a List.filter or List.partition function.
<d_bot> <romachkuna> yeah but i want to code it myself
<d_bot> <romachkuna> i already fixed it
<d_bot> <romachkuna> thanks
<Anarchos> romachkuna a known trick is to add h to an aux list, and then to List.rev the aux list
<Anarchos> so you remove becomes tail recursive and uses constant stack.
<d_bot> <NULL> Don't paste code, it spams IRC; I'm surprised no one complained in fact
<Anarchos> NULL even for 3 lines ?
<d_bot> <NULL> That's still ~5 messages in close succession; I wouldn't like it if it came from your side
jlrnick has joined #ocaml
Anarchos has quit [Quit: Vision[]: i've been blurred!]
kaph has quit [Read error: Connection reset by peer]
Tuplanolla has quit [Remote host closed the connection]
epony has quit [Quit: QUIT]
jlrnick has quit [Ping timeout: 248 seconds]
wyrd has quit [Ping timeout: 240 seconds]
kaph has joined #ocaml
wyrd has joined #ocaml
rgrinberg has quit [Quit: My MacBook has gone to sleep. ZZZzzz…]
kaph has quit [Remote host closed the connection]
kaph has joined #ocaml
mro has quit [Quit: Leaving...]
Haudegen has quit [Ping timeout: 246 seconds]
motherfsck has joined #ocaml
szkl has quit [Quit: Connection closed for inactivity]
epony has joined #ocaml