Logs: liberachat/#haskell
| 2026-03-07 12:36:52 | → | Tuplanolla joins (~Tuplanoll@88-114-89-88.elisa-laajakaista.fi) |
| 2026-03-07 12:39:11 | → | merijn joins (~merijn@62.45.136.136) |
| 2026-03-07 12:43:53 | → | wootehfoot joins (~wootehfoo@user/wootehfoot) |
| 2026-03-07 12:45:36 | <Leary> | Guest89: All of your data is lazy, even `Uid`; `data Uid = Uid {-# UNPACK #-} !(Int, Int)` is essentially equivalent to `data Uid = Uid Int Int`. If you're not utilising that laziness, kill it with strictness annotations. |
| 2026-03-07 12:46:08 | × | merijn quits (~merijn@62.45.136.136) (Ping timeout: 252 seconds) |
| 2026-03-07 12:48:05 | → | arandombit joins (~arandombi@user/arandombit) |
| 2026-03-07 12:51:29 | <Guest89> | I presume you mean at a function level? |
| 2026-03-07 12:51:34 | <Guest89> | I assumed the unpack itself made it strict |
| 2026-03-07 12:53:19 | <Leary> | No, the data constructors. `data Uid = Uid !Int !Int`; `data Ptr = PtrLeaf !Bool | PtrNode !Uid`; etc. |
| 2026-03-07 12:53:38 | <Guest89> | so what does unpack do in this case? |
| 2026-03-07 12:54:07 | <Guest89> | does it just transform the constructor into another one with the same arity as the tuples? |
| 2026-03-07 12:54:20 | <int-e> | yes |
| 2026-03-07 12:54:24 | <Leary> | `UNPACK` is only a hint for the compiler; it can't fundamentally change the semantics, which include the fields of `(,)` being lazy---that blocks any further unpacking. |
| 2026-03-07 12:55:10 | <Guest89> | right, but bangs force a semantics change? |
| 2026-03-07 12:55:36 | <Leary> | Yes. |
| 2026-03-07 12:56:06 | <Guest89> | I will play around and see what changes |
| 2026-03-07 12:56:38 | <int-e> | if you have data X = X (Int,Int) and data Y = Y !(Int,Int) then the difference is that you can have an `X bottom` value that's distinct from bottom, but `Y bottom` is just bottom. |
| 2026-03-07 12:56:55 | <int-e> | But you can still have Y (bottom, bottom) |
| 2026-03-07 12:57:07 | → | merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl) |
| 2026-03-07 12:57:27 | <Guest89> | I haven't really figured how you can even get bottom in practice |
| 2026-03-07 12:57:54 | <int-e> | And for a lazy language, you can also have thunks whereever bottoms can go, so you can't unpack anything in those places. |
| 2026-03-07 12:58:02 | <int-e> | > undefined |
| 2026-03-07 12:58:03 | <lambdabot> | *Exception: Prelude.undefined |
| 2026-03-07 12:58:03 | <lambdabot> | CallStack (from HasCallStack): |
| 2026-03-07 12:58:03 | <lambdabot> | undefined, called at <interactive>:3:1 in interactive:Ghci1 |
| 2026-03-07 12:58:05 | <int-e> | > fix id |
| 2026-03-07 12:58:12 | <lambdabot> | *Exception: <<timeout>> |
| 2026-03-07 12:58:29 | <Guest89> | fair point |
| 2026-03-07 12:58:31 | <int-e> | (Those are the usual manifestations in Haskell: an explicit error value, or nontermination) |
| 2026-03-07 12:58:56 | <Guest89> | guess I assumed it to be semantically different from an exception but I think I get what you mean |
| 2026-03-07 12:59:45 | <Guest89> | I guess the point is that you prefer strict data when it contains primitives? |
| 2026-03-07 13:00:03 | <int-e> | yes, usually |
| 2026-03-07 13:00:13 | <Guest89> | makes sense I suppose |
| 2026-03-07 13:00:24 | <haskellbridge> | <loonycyborg> > length [undefined, undefined, undefined] |
| 2026-03-07 13:00:31 | <haskellbridge> | <loonycyborg> hmm |
| 2026-03-07 13:00:43 | <haskellbridge> | <loonycyborg> it ate '>' |
| 2026-03-07 13:00:59 | <Guest89> | and I guess the same if you have strict data in another type? |
| 2026-03-07 13:01:22 | <int-e> | (Unpacking isn't completely free: If you unpack and later repack a value, that means a new heap object has to be created for it. This is why for data, GHC only does it when you give it a hint to do so.) |
| 2026-03-07 13:01:38 | × | merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds) |
| 2026-03-07 13:01:45 | <__monty__> | loonycyborg: No, the Matrix bridge is a single bot IRC-side. So your messages are prefixed with your nick. |
| 2026-03-07 13:02:24 | <haskellbridge> | <loonycyborg> is there a way to interact with lambabot from matrix? |
| 2026-03-07 13:05:16 | <Leary> | I gather you just need to put the command in a second line. |
| 2026-03-07 13:05:57 | → | tremon joins (~tremon@83.80.159.219) |
| 2026-03-07 13:06:27 | <__monty__> | Isn't each line prefixed? |
| 2026-03-07 13:09:23 | <[exa]> | tusko: do write in other languages to learn and appreciate the difference. :] |
| 2026-03-07 13:11:33 | <Leary> | __monty__: See this snippet I grepped from my logs: https://paste.tomsmeding.com/dXOuNbFn |
| 2026-03-07 13:13:10 | → | merijn joins (~merijn@62.45.136.136) |
| 2026-03-07 13:15:07 | <__monty__> | Ah, great, that should work for loonycyborg then. |
| 2026-03-07 13:17:21 | × | merijn quits (~merijn@62.45.136.136) (Ping timeout: 244 seconds) |
| 2026-03-07 13:22:25 | <haskellbridge> | <loonycyborg> > length [undefined, undefined, undefined] |
| 2026-03-07 13:22:36 | × | CiaoSen quits (~Jura@2a02:8071:64e1:da0:5a47:caff:fe78:33db) (Ping timeout: 264 seconds) |
| 2026-03-07 13:22:55 | <__monty__> | loonycyborg: Was that with a blank line? Maybe it can't be blank. |
| 2026-03-07 13:24:17 | → | merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl) |
| 2026-03-07 13:24:54 | <haskellbridge> | <loonycyborg> test |
| 2026-03-07 13:24:54 | <haskellbridge> | test |
| 2026-03-07 13:25:16 | <haskellbridge> | <loonycyborg> is one of those tests without prefix? |
| 2026-03-07 13:25:26 | <__monty__> | Yep, the latter. |
| 2026-03-07 13:26:11 | <int-e> | well, it had a leading space |
| 2026-03-07 13:26:14 | <haskellbridge> | <loonycyborg> test |
| 2026-03-07 13:26:14 | <haskellbridge> | length [undefined, undefined, undefined] |
| 2026-03-07 13:26:30 | <haskellbridge> | <loonycyborg> test |
| 2026-03-07 13:26:30 | <haskellbridge> | > length [undefined, undefined, undefined] |
| 2026-03-07 13:26:31 | <lambdabot> | 3 |
| 2026-03-07 13:26:50 | <haskellbridge> | <loonycyborg> hmm nice |
| 2026-03-07 13:26:55 | <[exa]> | Guest89: based on my experience on a similar project that allocated a lot, you really want to make the tuples strict. |
| 2026-03-07 13:27:17 | <haskellbridge> | <loonycyborg> > length [undefined, undefined, undefined] |
| 2026-03-07 13:28:19 | <[exa]> | ( "similar" based solely on fact I had complex IDs and a structure of them :D ) |
| 2026-03-07 13:28:55 | × | merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 245 seconds) |
| 2026-03-07 13:29:34 | <Guest89> | yeah I'm working on it exa; I'm not seeing as big a reduction in memory as I expected. seems more thunks are being allocated now instead |
| 2026-03-07 13:30:27 | <[exa]> | Guest89: do you have some compiler options that force it to specialize stuff? |
| 2026-03-07 13:30:35 | <Guest89> | not anything that specializes |
| 2026-03-07 13:30:38 | <[exa]> | Guest89: ( ghc-options: -O2 -fspecialise-aggressively -fexpose-all-unfoldings ) |
| 2026-03-07 13:30:57 | <Guest89> | I've got -O1 enabled atm but I didn't observe much when I tried -O2 |
| 2026-03-07 13:31:03 | <Guest89> | I can try some of the other settings later though |
| 2026-03-07 13:31:19 | <Guest89> | mostly I've tried to use pragmas to force things like inlining, but I haven't done anything to specialize |
| 2026-03-07 13:31:45 | <Guest89> | what are the benefits of specializing, exactly? |
| 2026-03-07 13:31:53 | × | arandombit quits (~arandombi@user/arandombit) (Ping timeout: 268 seconds) |
| 2026-03-07 13:31:57 | <[exa]> | in short ghc seemed quite lazy to inline stuff across modules unless I asked for it explicitly |
| 2026-03-07 13:32:17 | <[exa]> | if you specialize code you don't need to send the typeclass pointer around |
| 2026-03-07 13:32:31 | <[exa]> | and the specialized code is much more likely to realize that it can do stuff strictly |
| 2026-03-07 13:32:34 | <Guest89> | because it has a separate definition already? |
| 2026-03-07 13:32:38 | <Guest89> | from the specialization |
| 2026-03-07 13:32:43 | <[exa]> | yeah |
| 2026-03-07 13:32:43 | × | chromoblob quits (~chromoblo@user/chromob1ot1c) (Read error: Connection reset by peer) |
| 2026-03-07 13:32:45 | <Guest89> | hmm |
| 2026-03-07 13:33:00 | → | chromoblob joins (~chromoblo@user/chromob1ot1c) |
| 2026-03-07 13:33:06 | <Guest89> | you have to do twice the work though in terms of source code though, right? |
| 2026-03-07 13:33:38 | <[exa]> | like, the part with typeclass dictionaries getting passed around is not a huge deal, but in the end you may have 1 less allocation, and the possibility to specialize is open |
| 2026-03-07 13:33:54 | <[exa]> | yeah it may cost an extra copy of the code |
| 2026-03-07 13:34:20 | <[exa]> | (tbh my binary changed from like 9M to 9.5M when I was trying it, so I decided I don't care) |
| 2026-03-07 13:35:36 | <Guest89> | I'm doing this for my master's thesis, but I'll probably end up presenting a "clean" version that's semantically correct in the thesis itself and then using an optimized version for the actual benchmarks |
| 2026-03-07 13:35:53 | <Guest89> | my tl;dr is that the extra LOC should be whatever |
| 2026-03-07 13:36:39 | <[exa]> | Guest89: by "semantically correct" you mean "readable" :D |
| 2026-03-07 13:37:12 | → | CallipygousPepe joins (~reuben@user/CallipygousPepe) |
| 2026-03-07 13:37:45 | <Guest89> | well it's supposed to be an implementation that can be used as a jumping-off point if someone more nerdy about proofs would want to make a provably correct version |
| 2026-03-07 13:38:16 | <Guest89> | so compiler- or language-specific optimizations are kind of not the point there |
| 2026-03-07 13:38:23 | <[exa]> | anyway lots of the allocations in your profile actually seem to point to typeclass methods so I guess that a bit of specialization could help there |
| 2026-03-07 13:38:30 | <Guest89> | I will look into it |
| 2026-03-07 13:38:52 | × | madresch quits (~Thunderbi@user/madresch) (Ping timeout: 256 seconds) |
| 2026-03-07 13:38:53 | <Guest89> | inlining seemed to take the worst of the initial overhead (like 20% or something) but yeah, thunsk everywhere |
All times are in UTC.