<discocaml>
<masterbuilder> they are ok to use for primitive types though right?
<discocaml>
<masterbuilder> the normal equality operators
<discocaml>
<masterbuilder> why avoid them in all cases?
<discocaml>
<darrenldl> i guess easier to avoid it completely rather than spending time combing through your own code to make sure you only used it on primitive types
quernd85 has joined #ocaml
<discocaml>
<masterbuilder> sure I get that but it's only a problem for nontrivial data types and you know when you are using those right?
quernd8 has quit [Ping timeout: 246 seconds]
quernd85 is now known as quernd8
<discocaml>
<masterbuilder> or if it's a type you don't know anything about and want to play it safe
<discocaml>
<masterbuilder> but the regular types that you use all the time won't trip you up, so it seems a little paranoid
<discocaml>
<masterbuilder> but I guess the uniformity is nice in its own right
Anarchos has quit [Quit: Vision[]: i've been blurred!]
<discocaml>
<darrenldl> eh, it helps future refactoring
<discocaml>
<darrenldl> say when you replace a primitive type with something more complex
<discocaml>
<masterbuilder> I suppose that's true, but if you're doing that kind of refactor you can track down all the use sites rather than relying on compiler errors, though the latter is more convenient for sure
<discocaml>
<masterbuilder> but personally I don't think pessimizing the present for some hypothetical future is necessarily a good position, that's another type of paranoia, I guess if you don't care either way it's better to avoid it but I think using methods rather than operators is a bit of an eyesore
mima has quit [Ping timeout: 245 seconds]
waleee has quit [Ping timeout: 245 seconds]
<discocaml>
<btcflip> when is ocaml the right tool?
chrisz has quit [Ping timeout: 246 seconds]
chrisz has joined #ocaml
<discocaml>
<jumpnbrownweasel> @masterbuilder Containers and Base don't prevent you from using =, <, etc for scalars (int, float, bool, char), only for all other types (where this is risky and slow). so this provides a safeguard without any real downside. maybe you got that, but i wasn't sure.
<companion_cube>
@btcflip when is it not?
<discocaml>
<masterbuilder> I didn't know that actually, that is cool
<discocaml>
<btcflip> i guess my question is when or why would you confidently use ocaml over existing languages like node or go say if you were building a web server. what does it do better?
<companion_cube>
over node: correctness, speed
<companion_cube>
over go: idk, Go is pretty good for that stuff I suppose. But if you're doing more than just a web server, OCaml is nicer imho
<discocaml>
<btcflip> on another note, is `>>=` and `>|=` ocaml operators? they seem to be only used with lwt but can they be used outside of it
<companion_cube>
you can define them as operators in OCaml, and yes, lwt does define them
<companion_cube>
>>= is definitely used outside of lwt, it's the classic "monadic bind"
<discocaml>
<btcflip> thats pretty cool i didn't know you could define operators in ocaml, thats why i was so confused
John_Ivan has quit [Ping timeout: 250 seconds]
<companion_cube>
you can! there are restrictions, notably that the precedence (how it parses) is entirely determined by the first character of the operator
<companion_cube>
so `++!` will parse at the same level as `+`
companion_cube has quit [Quit: WeeChat 3.8]
discocaml has quit [Remote host closed the connection]
ocabot has quit [Remote host closed the connection]
TrillionEuroNote has quit [Ping timeout: 260 seconds]
TrillionEuroNote has joined #ocaml
spip has quit [Quit: Konversation terminated!]
azimut has quit [Ping timeout: 240 seconds]
<discocaml>
<bluddy5> It's very easy to make mistakes with the comparison operators. For example, a higher order function (which ocaml encourages for code reuse) may work well on some types, but will break subtly on other types. It's not even easy to reason about when comparison will break. Hashtables can seem to work for a while until they stop working, causing subtle bugs. And when you go back to change a primitive type to something else, will you remember to cha
<discocaml>
<bluddy5> This is why they should always be avoided.
Serpent7776 has joined #ocaml
mima has joined #ocaml
bartholin has joined #ocaml
cedric has joined #ocaml
cedric has quit [Quit: Konversation terminated!]
<qwr>
ocaml comparison operators are a bit weird in being a bit pseudopolymorphic, afaik compiler uses single implementation that operates on runtime memory layout with basically no type information (it follows pointers the same way as GC)
<qwr>
that's why it can break with some types and is suppressed in some alternative libraries like ocaml core
<qwr>
but personally i find it too convenient to use :)
<qwr>
the implementation follows from not having overloading, so these have to be parametrically polymorphic, and ocaml erases the types at runtime without monomorphisation, i.e. the runtime code is single instance that generally won't know the actual types
<qwr>
(which keeps emitted code size down, and makes fast incremental compilation easy, but its tradeoff like always)
spip has joined #ocaml
<steenuil>
I'm trying to decide how to structure the API for the X11 bindings I'm writing. the protocol consists in sending requests to a socket and getting back a response or an error with the same "sequence number" and also events
<steenuil>
does requiring the user to spin up a background Lwt thread (or whatever they're called) that reads responses sound reasonable? I'd like it to have a simple request-response API for the general use case
<steenuil>
where you can just call let* () = X11.create_window conn in ... or something like that
wingsorc__ has quit [Ping timeout: 246 seconds]
<steenuil>
then the current thread would write the request to the socket and the background thread would read the response and associate it with the request and send the reply (or an error) back and fulfill the Lwt value
rak has quit [Quit: Segmentation fault (core recycled)]
rak has joined #ocaml
<discocaml>
<froyo> Bluddy: stdlib containers have `equal` functions which take an equality predicate or implement their own equality via a functor provided `compare` + normalization... Hashtbl has a functor interface for similar reasons... I feel like polyeq fud is a bit overblown. Just need to be aware of it especially when designing your own (polymorphic) apis. As for "designing for the future", it probably is a bigger problem that you're exposing the internal
<discocaml>
<froyo>
<discocaml>
<froyo> polyeq is a nice compromise and I'll die on that hill lol
sagax has joined #ocaml
gareppa has joined #ocaml
<discocaml>
<bluddy5> I disagree. It's not enough to be aware of it either. If you use polymorphic equality, it will bite you at some point, and it could be when you least expect it. It could be when you have a whole system set up and running and it fails because someone used comparison over a list of maps, and it worked well until one day it didn't. This is the worst class of bugs, because you'll think everything is fine and your tests might pass, but out of the b
mima has quit [Ping timeout: 246 seconds]
<discocaml>
<leviroth> @jumpnbrownweasel : that thing about scalars is not true, at least in base. Base shadows polymorphic comparisons with ones that operate only on ints. To compare other types you need to get a comparison for that specific type (or recover polymorphic comparisons from the `Poly` module).
gareppa has quit [Quit: WeeChat 3.8]
gareppa has joined #ocaml
<discocaml>
<masterbuilder> that's a good point. I've been reading up on polymorphic compare more and I have to say it is quite shocking to find out how it is implemented. as for solving this problem, is there any reason why the compiler can't statically dispatch on the types and if they are compatible use the corresponding `equal`/`compare` functions if available (or for the built-in types use specialized comparison functions), and otherwise error? is it because i
<qwr>
consider let foo a b = a = b;; the function is polymorphic and the a = b callsite don't know anymore the type parameter, also passing (=)
<qwr>
i.e. imho this could work only with full monomorphisation of polymorphic functions
<qwr>
so the implementation is forced by one of the ground design decisions of how parametric polymorphism is implemented in the compiler
<qwr>
imho it could kind-of fixed by using overloading with the modular implicits proposal
<qwr>
but that wouldn't be backwards compatible
<qwr>
however, it would be possible then to have module that overrides the default (=)/(<>) definitons with more sane ones
<discocaml>
<bluddy5> Type classes were invented precisely to deal with this issue in haskell. Other functional languages piggyback on object-oriented mechanisms in their runtimes. OCaml can't directly support type classes and requires its analog, which is modular implicits (which you mention).
<discocaml>
<froyo> is it intentional that the types of possible printer functions aren't documented in the install_printer directive help docstring and error messages?
mima has joined #ocaml
<discocaml>
<octachron> Not really? This is probably more a case of uncaught assumptions (aka "what could it be except <insert the current answer whatever its degree of complexity>??" ) .
lilata has quit [Ping timeout: 252 seconds]
lilata has joined #ocaml
<discocaml>
<leviroth> @masterbuilder in general the problem with looking at the type and then picking “the” comparison function is that there can be more than one comparison function with the right type, and then what do you do? (And the same goes if you replace “comparison function” with “print function”, “module”, etc.) As you anticipate, modular implicits are an attempt to give a reasonable procedure for answering this question.
<companion_cube>
we really should just not mention modular implicits
bgs has joined #ocaml
<discocaml>
<jumpnbrownweasel> You're right it is only `int`, not all scalars, I'll edit and correct my message.
<discocaml>
<jumpnbrownweasel> @masterbuilder Containers and Base don't prevent you from using =, <, etc for `int` (edit: corrected this, it does not apply to other scalars). so this provides a safeguard without any real downside. maybe you got that, but i wasn't sure.
azimut has joined #ocaml
<discocaml>
<jumpnbrownweasel> One thing that's a little funny is that `Hashtbl` is always used as the example of where polymorphic `=` doesn't work, yet there is no `Hashtbl.equal` method to use as a substitute. It may be better to use `Map` and `Set` as the examples.
<discocaml>
<jumpnbrownweasel>
<discocaml>
<jumpnbrownweasel> I have implemented a `Hashtbl.equal` that I think is fairly efficient, but I don't know if it would be accepted in the stdlib.
<companion_cube>
how does it work? do you sort the individual buckets?
<discocaml>
<jumpnbrownweasel> Nope. It uses `iter` to walk through hashtbl A. When the key changes, it calls `find_all` on hashtbl B to get its list of values. A context ref is used to maintain the current key and list of values. When the key stays the same between iterations, it expects values to be iterated in the same order as in the value list. When a value matches it is popped from the list so at each iteration it checks the head of the list. It has to check
<companion_cube>
hmm
<discocaml>
<jumpnbrownweasel> The assumption is that two hash tables are equal if they have the same keys, and the same list of values per key in the same order. If the values were not in the same order, the behavior of the hashtables would be different.
gareppa has quit [Quit: WeeChat 3.8]
MarvelousWololo has joined #ocaml
John_Ivan has joined #ocaml
<discocaml>
<jumpnbrownweasel> I'll post the code in the containers channel in case you're interested.
<companion_cube>
sure :)
<companion_cube>
you probably need a bidirectional test, btw. Inclusion in both ways…
<discocaml>
<jumpnbrownweasel> The 1Hashtbl.length1s are compared up front. And if the value list length is different for a given key, the key comparison at each iteration will detect this.
<discocaml>
<jumpnbrownweasel> The `Hashtbl.length`s are compared up front. And if the value list length is different for a given key, the key comparison at each iteration will detect this.
azimut_ has joined #ocaml
azimut has quit [Ping timeout: 240 seconds]
gareppa has joined #ocaml
<discocaml>
<xavierm02_> @therewolf I can't think of an example where a type have two equality functions and it does not make sense to instead have two types with one equality per type. Do you have one in mind?
<discocaml>
<xavierm02_> My impression is that often, one of the equalities refines the other one, so that the type equipped with the latter can be though of as a quotient of the former, and it makes sense to abstract the quotient type to prevent it from being convertible to the initial type.
<discocaml>
<xavierm02_> (The only other case I can think of are int and uint, but I also believe that these should not be convertible)
<discocaml>
<xavierm02_> (Well for integers, the equality test is the same for both anyway)
<discocaml>
<octachron> You don't necessarily want to split a type in two just because you have two distinct equivalences on the type.
<discocaml>
<xavierm02_> (Well for integers, the equality test is the same for both anyway, but if you think more generally about typeclass they give an example of two incomparable notions of "less than" on the same type)
<discocaml>
<xavierm02_> @octachron Do you have a concrete example where you would not want to split the types?
<discocaml>
<jumpnbrownweasel> A partial comparator, for grouping, is one example.
<discocaml>
<hockletock> comparing vectors by magnitude
<discocaml>
<xavierm02_> Ok so like strings compared by their first letter.
<discocaml>
<xavierm02_> Hm
<discocaml>
<octachron> Polar coordinate: it might make sense to compare without the modulo 2π on the period because your points really live on a Riemannien surface and not the plane.
<discocaml>
<octachron> So you have two equivalences on your points: the projection on the plane, and the exact comparison and you might want to switch view on the same data.
<discocaml>
<xavierm02_> I'm starting to get my thoughts in order: If you have a type `t` with several equalities that are totally ordered, the equality you want to put in the typeclass ought to be obvious (the stricted one?).
<discocaml>
<xavierm02_> I'm starting to get my thoughts in order: If you have a type `t` with several equalities that are totally ordered, the equality you want to put in the typeclass ought to be obvious (the strictest one?).
<discocaml>
<octachron> Why impose a choice? Even more so when conversion is not free if you have containers where a deep identity traversal still requires a traversal.
<discocaml>
<xavierm02_> Well if you want to have a typeclass-like handling of `(=)`, you need to choose at most one equality per type to bind to `(=)`.
<discocaml>
<froyo> `Fun.on Vector.magnitude compare` if only... \😔
<discocaml>
<froyo> or `Fun.on (Fun.flip String.get 0) compare`
<discocaml>
<froyo> `(fun s -> s.[0])` did we deprecate that? idr
<discocaml>
<xavierm02_> In all examples so far, we have `eq2 x y = eq1 (f x) (f y)` for some easily-computable function `f`. Does anyone have an example where this is not the case?
<discocaml>
<octachron> Well, by definition, all cases are covered by your example with `eq1` = `eq2` and `f` = `Fun.id`.
mima has quit [Ping timeout: 246 seconds]
John_Ivan has quit [Quit: Disrupting the dragon's slumber one time too often shall eventually bestow upon all an empirical and indiscriminate conflagration that will last for all goddamn eternity.]
Techcable has joined #ocaml
<discocaml>
<octachron> No that was a bad argument. More meaningfully, you can have no meaningful equality of the full type, and different equivalences corresponding to different quotients. For instance, there is no good canonical equality on `float -> float`. You can devise a few equivalences however. For instance `f ~ g` if for any polynomial `p` of degree at most `k` `∫_[0,1] (f - g) p = 0` for a given numerical integration scheme.
gareppa has quit [Quit: WeeChat 3.8]
John_Ivan has joined #ocaml
mima has joined #ocaml
waleee has joined #ocaml
bartholin has quit [Ping timeout: 260 seconds]
bartholin has joined #ocaml
wingsorc__ has joined #ocaml
bgs has quit [Remote host closed the connection]
bartholin has quit [Quit: Leaving]
Serpent7776 has quit [Ping timeout: 246 seconds]
Tuplanolla has joined #ocaml
Anarchos has joined #ocaml
<Anarchos>
is there a mean to install an opam package without opam doing a tar of the whole installation ?
<discocaml>
<xavierm02_> Ah so basically an undecidable (or way too expensive to compute) equality that can be approximated by reasonable equivalences! There's indeed no reasonable choice of equality in these cases
Tuplanolla has quit [Quit: Leaving.]
Anarchos has quit [Quit: Vision[]: i've been blurred!]
Anarchos has joined #ocaml
jusensei2 has joined #ocaml
<jusensei2>
Hi, I'm playing a game in which there's a server that receives messages via TCP and returns a secret if I send the right 4 digit combination. I wrote a program that sends each digit sequentially and it is very slow. I want to change my program so that I can have multiple open connections to the server which would speed up the time it takes for me
<jusensei2>
to guess the password. However, being new to Ocaml I'm not sure what library I should use to accomplish this. Some options seem to be eio and lwt. The eio documentation claims that it replaces lwt so I am inclined to use that one but I would like to hear some suggestions. Any help would be appreciated, thank you :)
<jusensei2>
Slight typo: I meant to say that my initial program sends each combination sequentially (ie 0000, 0001, 0002, etc)