Home liberachat/#haskell: Logs Calendar

Logs: liberachat/#haskell

←Prev  Next→ 1,790,856 events total
2026-04-09 11:32:49 <mauke> Milan_Vanca: that's not a function
2026-04-09 11:32:50 <Freakie> i mean heavy wouldn't be a function, it would just be an expression
2026-04-09 11:33:59 <Freakie> if you're unsure you can always write some code that calls it and add some debug traces
2026-04-09 11:35:49 <Freakie> also I've asked before but I'm hoping someone knows more than I do; does anyone know of an effective way to link dependencies installed through cabal when doing FFI from Haskell to C++?
2026-04-09 11:36:16 <Milan_Vanca> mauke: Is the distiction necessary?
2026-04-09 11:36:36 <Freakie> the only way I've found to do it seems to be to manually give the install locations as arguments during the linking phase but that is extremely cumbersome and error-prone
2026-04-09 11:36:57 <mauke> Milan_Vanca: depends. necessary for what?
2026-04-09 11:38:05 × myme quits (~myme@2a01:799:d5e:5f00:fdf3:5ded:cda8:566f) (Ping timeout: 245 seconds)
2026-04-09 11:38:58 <Milan_Vanca> heavy_pi :: Double main = print heavy_pi; print heavy_pi...
2026-04-09 11:39:09 myme joins (~myme@2a01:799:d5e:5f00:374a:96c4:fb0d:7007)
2026-04-09 11:39:51 <Milan_Vanca> maybe i am missing "do"
2026-04-09 11:41:00 <Freakie> you need do notation when in the IO monad
2026-04-09 11:41:01 × troydm quits (~troydm@user/troydm) (Quit: What is Hope? That all of your wishes and all of your dreams come true? To turn back time because things were not supposed to happen like that (C) Rau Le Creuset)
2026-04-09 11:41:28 <Freakie> to answer your question though, pure expressions will only be evaluated once (heavy_pi :: Double etc)
2026-04-09 11:41:30 <mauke> you never "need" do notation
2026-04-09 11:42:02 <tomsmeding> Milan_Vanca: using a variable name multiple times does not result in its definition being computed multiple times, except when that variable is secretly a function
2026-04-09 11:42:48 <mauke> (where "secretly a function" is that class constraints thing I was talking about)
2026-04-09 11:42:56 <tomsmeding> variables can be secretly functions if they are actually polymorphic with a typeclass argument, such as `x = 4`
2026-04-09 11:43:18 <tomsmeding> there we have `x :: Num a => a`, and x's value is different for each type you can fill in for `a`
2026-04-09 11:43:26 <Milan_Vanca> so x in your example is function and wont be reused?
2026-04-09 11:43:42 <tomsmeding> thus it's really a function: from the "Num a" evidence to the resulting value; the `=>` arrow should be read as a function arrow here
2026-04-09 11:43:53 <tomsmeding> Milan_Vanca: indeed, because it _cannot_ be reused: its value is different at different types 'a'!
2026-04-09 11:44:20 <mauke> well...
2026-04-09 11:44:22 <tomsmeding> what GHC _could_ do is reuse x when used twice at the same type; whether that actually happens depends on what GHC's optimiser decides to do, no guarantees
2026-04-09 11:44:30 <Freakie> I mean if called with the same type argument it should reuse the expression?
2026-04-09 11:44:31 <Milan_Vanca> yeah but in example of main = do print x; print x it is always same right? should not be reevaluated?
2026-04-09 11:44:35 <mauke> functions are also reused
2026-04-09 11:44:50 <mauke> but it sounds like you're talking about the result of a function
2026-04-09 11:45:14 <Freakie> if x is a value from a non-deterministic monad it should be recomputed
2026-04-09 11:45:25 <tomsmeding> assuming you mean `print (x :: Int)`, that compiles to something like `main = print (x dNumInt) >> print (x dNumInt)`, where dNumInt is the "Num Int" type class dictionary (evidence)
2026-04-09 11:45:26 <mauke> Freakie: ?
2026-04-09 11:45:59 haritz joins (~hrtz@2a01:4b00:bc2e:7000:d5af:a266:ca31:5ef8)
2026-04-09 11:45:59 × haritz quits (~hrtz@2a01:4b00:bc2e:7000:d5af:a266:ca31:5ef8) (Changing host)
2026-04-09 11:45:59 haritz joins (~hrtz@user/haritz)
2026-04-09 11:46:00 <tomsmeding> then GHC can decide to do common subexpression elimination, and rewrite that to `main = let x' = x dNumInt in print x' >> print x'`, but GHC may or may not decide to do this
2026-04-09 11:46:21 <tomsmeding> at which point, `x' :: Int` and is a normal variable, so that `print x' >> print x'` will definitely compute x only once
2026-04-09 11:47:10 <tomsmeding> Freakie: the only way I can make sense of that is `unsafePerformIO (uniform <$> newStdGen)` or whatever the precise API is of System.Random
2026-04-09 11:47:23 <Freakie> would it have to use unsafePerformIO?
2026-04-09 11:47:24 <tomsmeding> in which case, well, you're using unsafePerformIO, you better know what you're doing
2026-04-09 11:47:29 <Milan_Vanca> what about main = do print x; print x; ... lot of other code; print x will last x be kept or recomputed?
2026-04-09 11:47:37 <tomsmeding> Freakie: yes, because without IO, everything is pure and hence deterministic
2026-04-09 11:47:40 <mauke> Milan_Vanca: depends on the type of x
2026-04-09 11:48:03 <tomsmeding> if x has a monomorphic type, reused; if x has a polymorphic type with type class constraints, recomputed (likely)
2026-04-09 11:48:04 <Milan_Vanca> the same as first one
2026-04-09 11:48:12 <mauke> first what?
2026-04-09 11:48:29 <Freakie> tomsmeding we're not strictly talking purity here though
2026-04-09 11:48:51 <Milan_Vanca> tomsmeding showed that x will be computed only once.. so first 2 will be reused then forgoten then recomputed?
2026-04-09 11:49:03 <mauke> what
2026-04-09 11:49:11 <tomsmeding> Milan_Vanca: no, you cannot say anything about your example unless you know what the type of x is
2026-04-09 11:49:24 <tomsmeding> if x :: Int, then x will be computed only once
2026-04-09 11:49:33 Enrico63 joins (~Enrico63@host-212-171-80-94.pool212171.interbusiness.it)
2026-04-09 11:49:43 <Freakie> it's also tricky because if you assume *any* number of instructions you can't say anything register allocation
2026-04-09 11:49:44 <tomsmeding> if x :: Num a => a, or Show a => [a], or something like that, then it will (likely!) be recomputed
2026-04-09 11:49:53 <Freakie> if it can't fit in the registers it will have to be recomputed
2026-04-09 11:49:55 <Freakie> (I think)
2026-04-09 11:49:59 <mauke> Freakie: ???
2026-04-09 11:50:06 <Milan_Vanca> ?
2026-04-09 11:50:18 <tomsmeding> Freakie: we're talking about the semantic level here, where reading the value from memory doesn't count as recomputation
2026-04-09 11:50:38 <Freakie> i guess memoization invalidates what I just said yeah
2026-04-09 11:50:39 <tomsmeding> if you want to know whether a memory read will occur, well, good luck reading the assembly, no guarantees
2026-04-09 11:51:00 <tomsmeding> (that's like 4 abstraction levels down suddenly from what we were talking about_)
2026-04-09 11:51:08 <Milan_Vanca> what about this?
2026-04-09 11:51:10 <Milan_Vanca> https://paste.tomsmeding.com/resvyMiU
2026-04-09 11:51:22 <tomsmeding> Milan_Vanca: precisely that code, without any type annotations?
2026-04-09 11:51:30 <mauke> depends on the type of x
2026-04-09 11:51:37 <mauke> which depends on whether the monomorphism restriction is on
2026-04-09 11:51:38 <Milan_Vanca> Lets say yes
2026-04-09 11:52:01 <tomsmeding> if precisely that code, then `x = 4` desugars to `x = fromInteger (4::Integer)`, and you get `x :: Num a => a`
2026-04-09 11:52:04 <Milan_Vanca> mauke: Can I decide if it is on or not?
2026-04-09 11:52:17 <tomsmeding> that call `fromInteger (4::Integer)` will likely be recomputed, but whether that actually happens depends on the GHC optimiser
2026-04-09 11:52:55 <mauke> Milan_Vanca: yes, https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/monomorphism.html#extension-MonomorphismRestriction
2026-04-09 11:53:01 <mauke> turning it off is a language extension
2026-04-09 11:53:26 <tomsmeding> oh, mauke is right
2026-04-09 11:53:32 __monty__ joins (~toonn@user/toonn)
2026-04-09 11:53:53 <tomsmeding> x will get a monomorphic type here (probably defaulting to Integer) because MonomorphismRestriction is on by default
2026-04-09 11:54:16 <mauke> with MR on, it kinda desugars to 'x = fromInteger (4::Integer) :: Integer' :-)
2026-04-09 11:54:42 <tomsmeding> at which point the fromInteger is likely optimised away, but that's irrelevant to the point of whether things are computed once or more than once
2026-04-09 11:54:44 <mauke> except '4::Integer' is not actually expressible in Haskell; it's a native Integer literal
2026-04-09 11:54:48 <tomsmeding> yeah
2026-04-09 11:54:54 <Milan_Vanca> I haven't disabled it so I guess it is enabled and thus x will be recomputed... got it.. Had I done something like this
2026-04-09 11:54:59 <Milan_Vanca> https://paste.tomsmeding.com/U94PhW5b
2026-04-09 11:55:11 <tomsmeding> Milan_Vanca: no, MR is enabled so x will NOT be recomputed
2026-04-09 11:55:13 <tomsmeding> please read
2026-04-09 11:55:14 <mauke> Milan_Vanca: no, MR prevents recomputation of x
2026-04-09 11:55:40 <tomsmeding> yep, in that example x will be computed once, and it's clearer from the source that that is os
2026-04-09 11:55:42 <tomsmeding> *so
2026-04-09 11:56:28 <tomsmeding> in general, whether a value is recomputed or not in haskell depends on the type of things and whether things are in the same scope, not how much code is in between the references
2026-04-09 11:56:34 <tomsmeding> there's no "limited-time caching" going on
2026-04-09 11:57:11 <tomsmeding> there could be, if you interpret the semantics loosely, but that would result in extremely unpredictable performance and memory use and hence GHC does not do that
2026-04-09 11:57:29 <tomsmeding> (there's enough unpredictability as it is)
2026-04-09 11:59:13 <Milan_Vanca> So basically If instead of X I allocated gigantic bytestring.. it would be ketp in memory for whole time program is running?
2026-04-09 11:59:34 <tomsmeding> until you don't have any references to it any more
2026-04-09 11:59:44 <mauke> yes
2026-04-09 11:59:46 <tomsmeding> because once a value has no references to it any more, the garbage collector (GC) cleans it up
2026-04-09 12:00:44 <Milan_Vanca> I thought so.. what about this example https://paste.tomsmeding.com/C5RBYVCY
2026-04-09 12:01:00 <Milan_Vanca> There is recursion.. and there is only one reference to x
2026-04-09 12:01:09 <Milan_Vanca> This must be recomputed multiple times right?
2026-04-09 12:01:18 <merijn> No
2026-04-09 12:01:33 <mauke> you can test it, btw
2026-04-09 12:01:44 <merijn> `x` is not polymorphic and not "function-like" so the MMR doesn't apply

All times are in UTC.