| 2026-01-18 00:00:53 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> the idea is (and it works and speeds up runtime considerably) that I add lots of INLINEs and INLINEABLE and then in each line starting with "Is @<some type>" a function is either inlined or called (but with unfolding available), which GHC now sees operating at concrete type, so it specializes the function (or its inlining) to that specific type |
| 2026-01-18 00:01:30 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> this is a code base with a huge amount of existential types, which totally block any sane ways of specializing code |
| 2026-01-18 00:01:44 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> * specializing/monomorphizing |
| 2026-01-18 00:02:06 +0100 | humasect | (~humasect@dyn-192-249-132-90.nexicom.net) (Quit: Leaving...) |
| 2026-01-18 00:02:38 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2026-01-18 00:02:52 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> but if anybody has any other ideas how to avoid passing around explicit dictionaries but maintain the very abstract API, I'm all ears |
| 2026-01-18 00:05:18 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> because what I'm currently doing is seriously embarrassing |
| 2026-01-18 00:05:34 +0100 | <EvanR> | any time you pass around explicit dictionaries, can't it also be passing (perhaps hidden inside a data type) a record of things doing the implementation |
| 2026-01-18 00:06:38 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> that makes sense; let me think why not |
| 2026-01-18 00:07:35 +0100 | ethantwardy | (~user@user/ethantwardy) ethantwardy |
| 2026-01-18 00:09:58 +0100 | ethantwardy | (~user@user/ethantwardy) (Client Quit) |
| 2026-01-18 00:11:40 +0100 | target_i | (~target_i@user/target-i/x-6023099) (Quit: leaving) |
| 2026-01-18 00:13:13 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 00:14:14 +0100 | ethantwardy | (~user@user/ethantwardy) ethantwardy |
| 2026-01-18 00:15:01 +0100 | ethantwardy | (~user@user/ethantwardy) (Client Quit) |
| 2026-01-18 00:16:51 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> so, the only argument against I can find is circularity: say, I'm implementing indexing in fancy nested arrays (which is called 12! times in the benchmark I'm working on), the code for the indexing takes a dictionary for storable vectors (the arrays are represented as tuples of such vectors) and it's terribly slow when it has to access the dictionary each time it's called |
| 2026-01-18 00:17:26 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> if I understand your idea correctly, the nested array indexing code should instead take a dictionary that directly works on nested arrays, not vectors |
| 2026-01-18 00:18:13 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> but the nested array indexing code implements what should be in that dictionary --- I'd need a way to somehow boostrap this, recurse across a dictionary |
| 2026-01-18 00:18:24 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2026-01-18 00:18:34 +0100 | <EvanR> | holy moly |
| 2026-01-18 00:21:01 +0100 | <EvanR> | if you're combining implementations in a way to implement another implementation, you do want to use prudent "let" bindings to make sure you only access the dependent implementation once |
| 2026-01-18 00:21:14 +0100 | <EvanR> | instead of every time it's accessed |
| 2026-01-18 00:21:38 +0100 | <EvanR> | this assumes the dependent implementation isn't dynamically changing for the same data structure |
| 2026-01-18 00:22:27 +0100 | <EvanR> | dependency isn't dynamically changing* |
| 2026-01-18 00:22:50 +0100 | <monochrom> | Oh, like "f x = f (x - 1) + f (x - 1)" vs "f x = let y = f (x - 1) in y + y"? |
| 2026-01-18 00:22:54 +0100 | <EvanR> | as far as knot typing I don't know about this |
| 2026-01-18 00:22:58 +0100 | <EvanR> | tying |
| 2026-01-18 00:24:10 +0100 | <EvanR> | makeF add x = add (x - 1) (x + 1) |
| 2026-01-18 00:24:20 +0100 | <EvanR> | let f = makeF (+) |
| 2026-01-18 00:24:38 +0100 | <EvanR> | this might not apply exactly, I'm not sure I totally understand the situation |
| 2026-01-18 00:24:38 +0100 | <Leary> | Man of Letters (Mikolaj): Re monomorphising, I see, that's a bit unfortunate. You can perhaps get rid of those existentials by using suitable heterogeneous types instead. |
| 2026-01-18 00:24:53 +0100 | ethantwardy | (~user@user/ethantwardy) ethantwardy |
| 2026-01-18 00:25:34 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> Leary: where can I see an example of something like that? |
| 2026-01-18 00:27:55 +0100 | troydm | (~troydm@user/troydm) troydm |
| 2026-01-18 00:28:07 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> some of the existential types arise naturally from AST GADTs (I have multiple interpreters of deeply embedded DLS in the implementation) |
| 2026-01-18 00:29:01 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 00:30:01 +0100 | <Leary> | The classic example is `data HList f xs where { Nil :: HList f '[]; Cons :: f x -> HList f xs -> HList f (x:xs) }`, but you can do similarly for arbitrary ASTs by duplicating some of their structure on the type level in the same way. |
| 2026-01-18 00:30:03 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> e.g., I can't think how to get rid of the existentially bound types in the node |
| 2026-01-18 00:30:03 +0100 | <haskellbridge> | ... long message truncated: https://kf8nh.com/_heisenbridge/media/kf8nh.com/QetWxmpnbhshlldjxsPntKNj/OFJ7l1DSftE (5 lines) |
| 2026-01-18 00:30:32 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> ok, thank you, I will think about this |
| 2026-01-18 00:31:55 +0100 | ethantwardy | (~user@user/ethantwardy) (Quit: WeeChat 4.4.2) |
| 2026-01-18 00:32:18 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> EvanR: right, so that's precisely the purpose of my crude hack with duplicating functions (or function calls) and so helping GHC specialize each call at a concrete known type; let me explain: |
| 2026-01-18 00:33:13 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> in your example, by the well placed "let", you avoid one of the two applications of subtraction |
| 2026-01-18 00:33:51 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> in my case, by specializing/monomorphising, I get rid of more than one dictionary lookup/passing |
| 2026-01-18 00:34:08 +0100 | <EvanR> | that was monochroms version |
| 2026-01-18 00:34:21 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> oh, yes, right |
| 2026-01-18 00:34:33 +0100 | Inline | (~User@2001-4dd6-dd24-0-d5a6-802e-e6e6-ce59.ipv6dyn.netcologne.de) (Ping timeout: 256 seconds) |
| 2026-01-18 00:34:55 +0100 | ethantwardy | (~user@user/ethantwardy) ethantwardy |
| 2026-01-18 00:35:20 +0100 | <EvanR> | I was thinking that, for a given properly constructed implementation, you only do look ups into any implementation once per call to the API |
| 2026-01-18 00:35:43 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 00:35:44 +0100 | <EvanR> | for any of the types that have this api |
| 2026-01-18 00:35:47 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> anyway, sadly, while "let" can cache values, it can't cache the determination which dictionary to look up into and how to combine whatever has been obtained from the dictionary --- only the GHC magic can do that |
| 2026-01-18 00:36:01 +0100 | <EvanR> | :thonk: |
| 2026-01-18 00:36:28 +0100 | Zemy_ | (~Zemy@2600:100c:b04a:cc3c:2826:1bff:fef2:30a6) |
| 2026-01-18 00:37:22 +0100 | <EvanR> | I would guess whatever ghc magic that is can be "manually" coded into the implementations, but no bearing on how the effort compares |
| 2026-01-18 00:37:38 +0100 | Core3498 | (~Zemy@72.178.108.235) |
| 2026-01-18 00:37:40 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> and the same regarding knots --- Haskell recursion doesn't cut it, something involving GHC internals would be needed (or something totally out of the box like maybe the heterogeneous types idea once I understand it) |
| 2026-01-18 00:38:03 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> oh, yes, sure, e.g., you can manually write monomorphic code from the start |
| 2026-01-18 00:38:17 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> and I actually like that a lot |
| 2026-01-18 00:38:30 +0100 | <EvanR> | not monomorphic |
| 2026-01-18 00:39:01 +0100 | <EvanR> | polymorphic types can satisfy the same API as monomorphic types |
| 2026-01-18 00:39:02 +0100 | trickard | (~trickard@cpe-82-98-47-163.wireline.com.au) (Read error: Connection reset by peer) |
| 2026-01-18 00:39:14 +0100 | Core4452 | (~Zemy@2600:100c:b04a:cc3c:ac56:f4ff:fe3c:1c26) |
| 2026-01-18 00:39:15 +0100 | trickard_ | (~trickard@cpe-82-98-47-163.wireline.com.au) |
| 2026-01-18 00:39:42 +0100 | Zemy_ | (~Zemy@2600:100c:b04a:cc3c:2826:1bff:fef2:30a6) (Read error: Connection reset by peer) |
| 2026-01-18 00:39:44 +0100 | <EvanR> | e.g. addition interface could be implemented by Word8 or Complex a where a implements addition interface |
| 2026-01-18 00:40:04 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> yes, you are right, code without existentials, plus "-fexpose-overloaded-unfoldings" and "-fspecialise-aggressively" should in theory be just as good at avoiding runtime lookups |
| 2026-01-18 00:40:12 +0100 | Zemy | (~Zemy@72.178.108.235) (Ping timeout: 256 seconds) |
| 2026-01-18 00:41:10 +0100 | <EvanR> | aiui typeclasses shine in cases where you can get away without talking about explicit dictionaries, since it will be passed automagically around |
| 2026-01-18 00:41:26 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> yes, I fully agree |
| 2026-01-18 00:41:45 +0100 | bgamari | (~bgamari@64.223.170.198) (Quit: ZNC 1.8.2 - https://znc.in) |
| 2026-01-18 00:41:49 +0100 | Core3498 | (~Zemy@72.178.108.235) (Ping timeout: 246 seconds) |
| 2026-01-18 00:43:32 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> but once you start writing GADTs it's so hard to avoid existentials; I tried for a while, marked each one in the source code, but quickly gave up --- too many :) |
| 2026-01-18 00:44:07 +0100 | ethantwardy | (~user@user/ethantwardy) (Quit: WeeChat 4.4.2) |
| 2026-01-18 00:44:15 +0100 | vanishingideal | (~vanishing@user/vanishingideal) vanishingideal |
| 2026-01-18 00:44:27 +0100 | bgamari | (~bgamari@64.223.173.201) |
| 2026-01-18 00:44:29 +0100 | <geekosaur> | enh, you can enable GADTSyntax without enabling GADTs |
| 2026-01-18 00:45:40 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> oh no, but the sweet reward is in the extra type correctness real GADTs ensure, unlike GADTSyntax, especially for syntax-like things |
| 2026-01-18 00:46:18 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> I'd love to read some functional pearl that rewrites the classic GADT AST examples without existentials in some fancy way |
| 2026-01-18 00:46:36 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> in many plausible ways, preferably |
| 2026-01-18 00:46:52 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> with similar correctness guarantees |
| 2026-01-18 00:47:03 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 00:47:58 +0100 | <EvanR> | the GADTsyntax is besides the point, since the key thing is case analyzing to introduce the forgotten now unknown type... however it was defined and constructed |
| 2026-01-18 00:48:07 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> for a non-trivial AST (I don't remember Peano arithmetic or lambda calculus already have existential types in the classic encoding) |
| 2026-01-18 00:48:08 +0100 | <geekosaur> | I'm confused. Doesn't that extra correctness come specifically from the embedded existentials, which are exposed by scrutinizing constructors? |
| 2026-01-18 00:48:10 +0100 | <EvanR> | in cases where you use existentials |
| 2026-01-18 00:49:00 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> geekosaur: I'm afraid so, but maybe there is another way? |
| 2026-01-18 00:49:15 +0100 | <EvanR> | doing existentials without existentials sounds tricky |
| 2026-01-18 00:49:25 +0100 | <EvanR> | (and what's the point) |
| 2026-01-18 00:49:30 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> :D |
| 2026-01-18 00:50:23 +0100 | humasect | (~humasect@dyn-192-249-132-90.nexicom.net) humasect |
| 2026-01-18 00:50:59 +0100 | ethantwardy | (~user@user/ethantwardy) ethantwardy |
| 2026-01-18 00:51:37 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 246 seconds) |
| 2026-01-18 00:52:51 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> well, the point is, they are not a zero-cost abstraction unlike, in principle, most of other abstractions Haskell provides |
| 2026-01-18 00:53:47 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> and being so handy, they easily pollute the performance-sensitive parts of the application |
| 2026-01-18 00:55:03 +0100 | catties | kitties |
| 2026-01-18 00:55:27 +0100 | <geekosaur> | I think the only other alternative isn't here yet: dependent type witnesses of some kind. Which are also not zero cost, and I suspect end up being just a different way to encode existentials |
| 2026-01-18 00:56:30 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> ;< |
| 2026-01-18 00:57:23 +0100 | trickard_ | (~trickard@cpe-82-98-47-163.wireline.com.au) (Read error: Connection reset by peer) |
| 2026-01-18 00:57:37 +0100 | trickard_ | (~trickard@cpe-82-98-47-163.wireline.com.au) |
| 2026-01-18 00:58:10 +0100 | <geekosaur> | (GADT-style, at least) |
| 2026-01-18 00:58:18 +0100 | __monty__ | (~toonn@user/toonn) (Quit: leaving) |
| 2026-01-18 01:02:47 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 01:07:19 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 01:08:00 +0100 | <Leary> | Man of Letters (Mikolaj): Re the heterogeneous types, it's basically just a matter of building a home for your discarded types to live in. In the simplest case where all those types have the same kind, you could literally just add a type level list to your AST: `AstCastS :: (NumScalar r1, RealFrac r1, NumScalar r2, RealFrac r2) => AstTensor discarded ms s (TKS sh r1) -> AstTensor (r1:discarded) ms s (TKS sh r2)` |
| 2026-01-18 01:10:55 +0100 | ljdarj | (~Thunderbi@user/ljdarj) (Ping timeout: 244 seconds) |
| 2026-01-18 01:14:31 +0100 | qqq | (~qqq@185.54.21.105) (Quit: Lost terminal) |
| 2026-01-18 01:17:09 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 01:18:32 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> oh wow, thank you, that's interesting |
| 2026-01-18 01:20:00 +0100 | mhatta | (~mhatta@www21123ui.sakura.ne.jp) (Quit: ZNC 1.10.1+deb1 - https://znc.in) |
| 2026-01-18 01:20:19 +0100 | <haskellbridge> | <Man of Letters (Mikolaj)> falls more into the category of "ways to make existential-like things zero-cost" than the category "an alternative but similarly handy abstraction mechanism" |
| 2026-01-18 01:21:35 +0100 | takuan | (~takuan@d8D86B9E9.access.telenet.be) (Ping timeout: 245 seconds) |
| 2026-01-18 01:22:14 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 265 seconds) |
| 2026-01-18 01:24:23 +0100 | poscat | (~poscat@user/poscat) (Remote host closed the connection) |
| 2026-01-18 01:25:43 +0100 | mhatta | (~mhatta@www21123ui.sakura.ne.jp) |
| 2026-01-18 01:27:33 +0100 | poscat | (~poscat@user/poscat) poscat |
| 2026-01-18 01:31:08 +0100 | trickard_ | trickard |
| 2026-01-18 01:32:56 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 01:38:19 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2026-01-18 01:38:48 +0100 | machinedgod | (~machinedg@d75-159-126-101.abhsia.telus.net) machinedgod |
| 2026-01-18 01:43:04 +0100 | vanishingideal | (~vanishing@user/vanishingideal) (Ping timeout: 246 seconds) |
| 2026-01-18 01:43:05 +0100 | droideqa | (uid499291@user/droideqa) (Quit: Connection closed for inactivity) |
| 2026-01-18 01:43:25 +0100 | Zemy | (~Zemy@72.178.108.235) |
| 2026-01-18 01:44:59 +0100 | vanishingideal | (~vanishing@user/vanishingideal) vanishingideal |
| 2026-01-18 01:47:16 +0100 | Core4452 | (~Zemy@2600:100c:b04a:cc3c:ac56:f4ff:fe3c:1c26) (Ping timeout: 246 seconds) |
| 2026-01-18 01:48:43 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 01:50:11 +0100 | <monochrom> | Existentials are zero-cost iff unusable. |
| 2026-01-18 01:51:58 +0100 | <monochrom> | an easy corollary of information theory. For a value to be usable, you must pass around sufficient information, thus the non-zero cost. |
| 2026-01-18 01:53:15 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 01:53:34 +0100 | <EvanR> | a value can have zero cost if the only possibility is that it exists i.e. () |
| 2026-01-18 01:53:52 +0100 | <EvanR> | sounds useful |
| 2026-01-18 01:54:07 +0100 | <monochrom> | A concrete example being: If you give me an existential value and want me to be able to use Show methods on it, then you must also give me the Show methods, lest how do I even know that I'm allowed to. |
| 2026-01-18 01:55:30 +0100 | <monochrom> | or at least a pointer to the struct of Show methods. |
| 2026-01-18 01:57:12 +0100 | <monochrom> | OK OK s/unusable/indistinguishable from ()/ :) |
| 2026-01-18 02:00:09 +0100 | Zemy_ | (~Zemy@2600:100c:b04a:cc3c:1015:34ff:fe46:86ce) |
| 2026-01-18 02:03:18 +0100 | vanishingideal | (~vanishing@user/vanishingideal) (Ping timeout: 252 seconds) |
| 2026-01-18 02:03:18 +0100 | Zemy | (~Zemy@72.178.108.235) (Ping timeout: 252 seconds) |
| 2026-01-18 02:03:30 +0100 | Zemy | (~Zemy@72.178.108.235) |
| 2026-01-18 02:04:30 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 02:06:55 +0100 | Zemy_ | (~Zemy@2600:100c:b04a:cc3c:1015:34ff:fe46:86ce) (Ping timeout: 264 seconds) |
| 2026-01-18 02:06:58 +0100 | skum | (~skum@user/skum) (Quit: WeeChat 4.8.1) |
| 2026-01-18 02:10:35 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 02:22:03 +0100 | vanishingideal | (~vanishing@user/vanishingideal) vanishingideal |
| 2026-01-18 02:22:32 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 02:24:45 +0100 | divlamir | (~divlamir@user/divlamir) (Read error: Connection reset by peer) |
| 2026-01-18 02:25:10 +0100 | divlamir | (~divlamir@user/divlamir) divlamir |
| 2026-01-18 02:27:15 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 02:31:54 +0100 | emmanuelux | (~em@user/emmanuelux) (Quit: bye) |
| 2026-01-18 02:32:08 +0100 | emmanuelux | (~em@user/emmanuelux) emmanuelux |
| 2026-01-18 02:38:17 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 02:40:02 +0100 | emmanuelux | (~em@user/emmanuelux) (Quit: bye) |
| 2026-01-18 02:40:15 +0100 | emmanuelux | (~em@user/emmanuelux) emmanuelux |
| 2026-01-18 02:42:55 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 02:44:17 +0100 | acidjnk | (~acidjnk@p200300d6e7171955902046af4b3b27fd.dip0.t-ipconnect.de) (Ping timeout: 250 seconds) |
| 2026-01-18 02:49:48 +0100 | omidmash0 | (~omidmash@user/omidmash) omidmash |
| 2026-01-18 02:50:39 +0100 | Square2 | (~Square@user/square) (Ping timeout: 260 seconds) |
| 2026-01-18 02:52:24 +0100 | omidmash | (~omidmash@user/omidmash) (Ping timeout: 260 seconds) |
| 2026-01-18 02:52:24 +0100 | omidmash0 | omidmash |
| 2026-01-18 02:54:04 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 02:58:40 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 246 seconds) |
| 2026-01-18 03:06:13 +0100 | Tuplanolla | (~Tuplanoll@85-156-32-207.elisa-laajakaista.fi) (Quit: Leaving.) |
| 2026-01-18 03:09:52 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 03:10:30 +0100 | trickard | (~trickard@cpe-82-98-47-163.wireline.com.au) (Read error: Connection reset by peer) |
| 2026-01-18 03:10:44 +0100 | trickard_ | (~trickard@cpe-82-98-47-163.wireline.com.au) |
| 2026-01-18 03:14:35 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 03:17:30 +0100 | Inline | (~User@2001-4dd6-dd24-0-5713-7235-9889-58da.ipv6dyn.netcologne.de) Inline |
| 2026-01-18 03:25:38 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 03:30:15 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 240 seconds) |
| 2026-01-18 03:35:55 +0100 | vanishingideal | (~vanishing@user/vanishingideal) (Ping timeout: 240 seconds) |
| 2026-01-18 03:41:24 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 03:45:52 +0100 | jmcantrell_ | (~weechat@user/jmcantrell) jmcantrell |
| 2026-01-18 03:48:05 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 244 seconds) |
| 2026-01-18 03:48:13 +0100 | omidmash | (~omidmash@user/omidmash) (Quit: The Lounge - https://thelounge.chat) |
| 2026-01-18 03:51:36 +0100 | omidmash | (~omidmash@user/omidmash) omidmash |
| 2026-01-18 03:53:25 +0100 | emmanuelux | (~em@user/emmanuelux) (Quit: bye) |
| 2026-01-18 03:54:47 +0100 | emmanuelux | (~em@user/emmanuelux) emmanuelux |
| 2026-01-18 03:56:24 +0100 | emmanuelux | (~em@user/emmanuelux) (Remote host closed the connection) |
| 2026-01-18 03:59:26 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 04:00:17 +0100 | xff0x | (~xff0x@2405:6580:b080:900:c589:6b53:dd18:5a14) (Ping timeout: 265 seconds) |
| 2026-01-18 04:00:47 +0100 | xff0x | (~xff0x@2405:6580:b080:900:c180:d9e0:95c3:e24d) |
| 2026-01-18 04:00:55 +0100 | emmanuelux | (~em@user/emmanuelux) emmanuelux |
| 2026-01-18 04:03:01 +0100 | emmanuelux | (~em@user/emmanuelux) (Remote host closed the connection) |
| 2026-01-18 04:04:18 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 252 seconds) |
| 2026-01-18 04:05:03 +0100 | op_4 | (~tslil@user/op-4/x-9116473) (Remote host closed the connection) |
| 2026-01-18 04:05:35 +0100 | op_4 | (~tslil@user/op-4/x-9116473) op_4 |
| 2026-01-18 04:07:45 +0100 | vanishingideal | (~vanishing@user/vanishingideal) vanishingideal |
| 2026-01-18 04:14:58 +0100 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-01-18 04:16:14 +0100 | emmanuelux | (~em@user/emmanuelux) emmanuelux |