Home liberachat/#haskell: Logs Calendar

Logs: liberachat/#haskell

←Prev  Next→ 1,794,276 events total
2026-04-14 06:47:45 sord937 joins (~sord937@gateway/tor-sasl/sord937)
2026-04-14 06:48:05 <[exa]> mornin'
2026-04-14 06:51:05 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-14 06:56:09 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds)
2026-04-14 07:05:08 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-14 07:11:49 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 244 seconds)
2026-04-14 07:17:36 uli-fem joins (~uli-fem@203.87.114.209)
2026-04-14 07:18:21 Milan_Vanca joins (~milan@user/Milan-Vanca:32634)
2026-04-14 07:19:25 × sord937 quits (~sord937@gateway/tor-sasl/sord937) (Remote host closed the connection)
2026-04-14 07:20:55 CiaoSen joins (~Jura@p549cbfb1.dip0.t-ipconnect.de)
2026-04-14 07:20:58 sord937 joins (~sord937@gateway/tor-sasl/sord937)
2026-04-14 07:22:17 × uli-fem quits (~uli-fem@203.87.114.209) (Ping timeout: 248 seconds)
2026-04-14 07:25:43 <Milan_Vanca> Good morning guyz! The more I read, the more confusing all sharing and evaluation is :-(
2026-04-14 07:25:56 <Milan_Vanca> > let a = [1..3] :: [Int] in (length a :: Int) == (length a :: Int)
2026-04-14 07:25:58 <lambdabot> True
2026-04-14 07:26:26 <monochrom> That example is not confusing.
2026-04-14 07:26:31 <Milan_Vanca> Will length a be evaluated twice? In means will the list be traversed twice?
2026-04-14 07:27:56 <Milan_Vanca> My expectation is that as "a" is same.. so "length a" must be same.. and thus it will be evaluated only once and then passed to comparsion
2026-04-14 07:29:32 <[exa]> Milan_Vanca: in this case you don't do anything to tell the compiler to NOT evaluate it twice; but ghc may quite safely transform the code to something like `let a=[1..3] in let tmp=length a in tmp == tmp`
2026-04-14 07:30:49 × leppard quits (~noOne@ipservice-092-208-182-236.092.208.pools.vodafone-ip.de) (Ping timeout: 248 seconds)
2026-04-14 07:31:54 <[exa]> Milan_Vanca: the rule of thumb is "let-bindings create exactly one thunk". Once thunks get evaluated for the first time, they are _rewritten_ to their results, so evaluating them for the second time "does nothing". Which gives you a pretty good tool to make sure the `length` isn't going to execute twice
2026-04-14 07:33:26 × Sgeo quits (~Sgeo@user/sgeo) (Read error: Connection reset by peer)
2026-04-14 07:33:43 <Milan_Vanca> [exa]: Yeah.. I can follow that.. but my example bound only list to variable "let a = [1..3] :: [Int]"
2026-04-14 07:33:56 <[exa]> that's ok, the list is going to get materialized only once
2026-04-14 07:33:59 <Milan_Vanca> If I want to be sure it wont be evaluated twice I need to bound it myself right?
2026-04-14 07:34:20 <Milan_Vanca> I mean "length a"
2026-04-14 07:34:42 <Milan_Vanca> You said it "may" be evaluated once as ghc does some rewriting.
2026-04-14 07:35:20 <[exa]> yeah there's some optimizations that are able to uniquify common sub-expressions a little, so chances are it might do this for you. But that's hard to rely upon tbh.
2026-04-14 07:35:54 <[exa]> anyway yeah if you make a single binding for the `length a`, it should evaluate once
2026-04-14 07:37:49 <mra> Milan_Vanca: maybe a silly question, but why does it matter if it's evaluated twice?
2026-04-14 07:39:08 <[exa]> if the list is yuge, caching the O(n) length computation may help a lot
2026-04-14 07:39:43 <[exa]> (ofc assuming some other use-case than `len==len` :D )
2026-04-14 07:40:02 <Milan_Vanca> Well for simple problems it probably does not.. for real world programming I guess it does... I would like to use ghc/haskell with real world programs
2026-04-14 07:40:19 <Milan_Vanca> [exa]: :)
2026-04-14 07:40:23 <mra> i guess that's true, yeah. i would expect GHC to factor out the common subexpression, but i guess relying on that may be unwise
2026-04-14 07:41:50 uli-fem joins (~uli-fem@203.87.114.209)
2026-04-14 07:42:07 <Milan_Vanca> Examples.. I want to reuse one "http_manager" across different functions.. when manager is defined as let manager = getManager settings.. I want to be sure it is not always a new manager but the old manager with cached tcp connections.
2026-04-14 07:43:18 <[exa]> Milan_Vanca: in such case you might want to put the manager into some kind of MVar or IORef so that you can actually modify it later (assuming it doesn't do that internally)
2026-04-14 07:43:31 alter2000 joins (~alter2000@user/alter2000)
2026-04-14 07:43:47 <probie> It pretty much never factors out the common subexpression, since doing it carelessly can introduce space leaks. The programmer already has `let` at their disposal if that's the behaviour they want.
2026-04-14 07:44:02 <monochrom> Your example is empirically weird. (GHC 9.6.7 -O) The core code goes to the trouble of constructing [1..3] then evaluating its length. Then the answer is ignored, the code prints True without even comparing 3==3.
2026-04-14 07:44:11 <Milan_Vanca> Or just define it and then pass it to all functions that need it?
2026-04-14 07:44:25 leppard joins (~noOne@ipservice-092-208-182-236.092.208.pools.vodafone-ip.de)
2026-04-14 07:45:55 terrorjack joins (~terrorjac@2a01:4f8:271:2d98::2)
2026-04-14 07:46:09 × uli-fem quits (~uli-fem@203.87.114.209) (Ping timeout: 245 seconds)
2026-04-14 07:46:25 <mra> that seems messier than just wrapping it in IORef
2026-04-14 07:46:33 <Milan_Vanca> probie: So if I define top lvl function as a1 = [1..10^6] :: [Int] a2 = [1..10^6] :: [Int] there is not subexpresion elimination and in fact 2 big lists?
2026-04-14 07:46:47 <monochrom> In general, you can rely on reuse that you manually arranged for by aliasing. But you cannot rely on optimisers not being more aggressive than you.
2026-04-14 07:47:00 <Milan_Vanca> monochrom: really?
2026-04-14 07:47:52 <Milan_Vanca> why is my example empirically weird? why it wont evaluate 3==3?
2026-04-14 07:48:05 <Milan_Vanca> Like is it optimization that is sees whatever it is it must be true?
2026-04-14 07:48:17 × jreicher quits (~joelr@user/jreicher) (Quit: In transit)
2026-04-14 07:48:35 <Milan_Vanca> > (error "a" :: Int) == (error "a" :: Int)
2026-04-14 07:48:36 <lambdabot> *Exception: a
2026-04-14 07:48:36 <lambdabot> CallStack (from HasCallStack):
2026-04-14 07:48:36 <lambdabot> error, called at <interactive>:3:2 in interactive:Ghci1
2026-04-14 07:48:41 <Milan_Vanca> no it must evaluate
2026-04-14 07:48:47 <Milan_Vanca> ah no
2026-04-14 07:48:49 <monochrom> I don't know of any answer other than "read GHC source code".
2026-04-14 07:48:55 <Milan_Vanca> :D
2026-04-14 07:49:02 <Milan_Vanca> hmmm
2026-04-14 07:49:06 <Milan_Vanca> yeah ty
2026-04-14 07:49:25 <Milan_Vanca> So I can use aliasing and naming to explicitly say what I want to share
2026-04-14 07:49:28 <Milan_Vanca> got it :)
2026-04-14 07:50:35 <probie> Milan_Vanca: In your example there are two distinct thunks. There aren't any big lists until someone starts doing something with them. Sharing those would be a bad idea if you didn't know how they were going to be used
2026-04-14 07:50:49 <monochrom> or "take a code optimization course to learn that beyond the obvious you must start using heuristics that are full of false positives and false negatives and by the time you have 100 heuristics it begins to behave like randomized LLMs".
2026-04-14 07:52:53 <probie> You might end up with a big list in a case where if they weren't shared, no big list ever needed to exist in memory e.g. if you've got a reference to `a1` and have evaluated `last a2` to WHNF, if they're the same list, that reference to a1 means you can't garbage collect the list spine you evaluated as part of `last a2`
2026-04-14 07:53:26 <gentauro> I have setup emacs (I run in a terminal) with LSP to give minimalistic messages (example: Found hole: _ :: [Int] -> Int) to avoid too much "bloated" LSP stuff. However, sometimes, I would like to get the full message. Anybody know a key-combination for that?
2026-04-14 07:53:28 <probie> If in the end, the way you use `a1` is simply something like `head a1`; you've just been carrying around a big list for absolutely no reason
2026-04-14 07:53:44 <Milan_Vanca> monochrom: sounds scary :D
2026-04-14 07:54:45 × leppard quits (~noOne@ipservice-092-208-182-236.092.208.pools.vodafone-ip.de) (Quit: KVIrc 5.0.0 Aria http://www.kvirc.net/)
2026-04-14 07:55:05 <Milan_Vanca> probie: that makes sense and that is why I want to know how something works.
2026-04-14 07:55:12 merijn joins (~merijn@77.242.116.146)
2026-04-14 07:56:05 <Milan_Vanca> probie: Either one might end up with 2x times the memory.. or retain something in memory longer.
2026-04-14 07:56:19 Googulator55 joins (~Googulato@94-21-172-213.pool.digikabel.hu)
2026-04-14 08:00:12 × Googulator quits (~Googulato@94-21-172-213.pool.digikabel.hu) (Ping timeout: 245 seconds)
2026-04-14 08:00:17 <Milan_Vanca> I did let a = 1 + 1 :: Int let b = 1 + 1 :: Int; seq b (); :sprint a; and it showed still as thunk and that confused me
2026-04-14 08:00:50 <Milan_Vanca> Anyway I think I know why.. a and b never pointed to same thunk in the first place
2026-04-14 08:00:59 <Milan_Vanca> ty guyz :)
2026-04-14 08:01:41 uli-fem joins (~uli-fem@203.87.114.209)
2026-04-14 08:03:17 <monochrom> I am much less surprised because I've seen GCC done similar weird things before. I had "int x=1; int i=0; while (x>=0) {x*=2; ++i;} print i". gcc -O turned it into "for (i=0; i<31; i++)". gcc -O2 recognized "strictly speaking UB" so turned it into "L2: jmp L2"
2026-04-14 08:06:27 × uli-fem quits (~uli-fem@203.87.114.209) (Ping timeout: 272 seconds)
2026-04-14 08:11:14 × emmanuelux quits (~em@user/emmanuelux) (Quit: bye)
2026-04-14 08:11:32 jreicher joins (~joelr@user/jreicher)
2026-04-14 08:14:54 karenw joins (~karenw@user/karenw)
2026-04-14 08:18:43 chewybread joins (~chewybrea@240b:10:9502:4100:cc55:2129:18be:80a5)
2026-04-14 08:18:43 × chewybread quits (~chewybrea@240b:10:9502:4100:cc55:2129:18be:80a5) (Changing host)
2026-04-14 08:18:43 chewybread joins (~chewybrea@user/chewybread)
2026-04-14 08:19:30 × s3 quits (~s3@user/bn) (Ping timeout: 248 seconds)
2026-04-14 08:22:33 × tromp quits (~textual@2001:1c00:340e:2700:f5bd:97ff:8f76:c38c) (Quit: My iMac has gone to sleep. ZZZzzz…)
2026-04-14 08:27:55 × ft quits (~ft@p508db287.dip0.t-ipconnect.de) (Quit: leaving)
2026-04-14 08:28:48 DetourNe- joins (~DetourNet@user/DetourNetworkUK)
2026-04-14 08:28:55 × DetourNetworkUK quits (~DetourNet@user/DetourNetworkUK) (Read error: Connection reset by peer)
2026-04-14 08:31:02 DetourNe- is now known as DetourNetworkUK
2026-04-14 08:38:07 × chewybread quits (~chewybrea@user/chewybread) (Remote host closed the connection)
2026-04-14 08:42:33 uli-fem joins (~uli-fem@203.87.114.209)
2026-04-14 08:48:45 × alter2000 quits (~alter2000@user/alter2000) (Ping timeout: 255 seconds)
2026-04-14 08:49:31 × uli-fem quits (~uli-fem@203.87.114.209) (Ping timeout: 264 seconds)
2026-04-14 08:54:09 uli-fem joins (~uli-fem@203.87.114.209)
2026-04-14 08:54:50 arandombit joins (~arandombi@user/arandombit)

All times are in UTC.