2026/05/28

Newest at the top

2026-05-28 20:31:56 +0000takuan(~takuan@d8D86B9E9.access.telenet.be) (Ping timeout: 266 seconds)
2026-05-28 20:31:03 +0000merijn(~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn
2026-05-28 20:27:44 +0000pavonia(~user@user/siracusa) siracusa
2026-05-28 20:22:37 +0000 <int-e> Right. You get a fixed point combinator. You don't get sharing though. (yfix (1:) produces an infinite heap object)
2026-05-28 20:21:38 +0000peterbecich(~Thunderbi@71.84.33.135) peterbecich
2026-05-28 20:13:33 +0000 <mauke> https://en.wikipedia.org/wiki/Fixed-point_combinator#Type_for_the_Y_combinator
2026-05-28 20:12:18 +0000 <c_wraith> it still requires type recursion to work. The next trick is to reimplement type-level fix
2026-05-28 20:12:17 +0000tomsmeding. o O ( https://downloads.haskell.org/ghc/latest/docs/users_guide/bugs.html#bugs-in-ghc )
2026-05-28 20:11:41 +0000 <tomsmeding> oh, I've seen this before. The NOINLINE is the juicy part :)
2026-05-28 20:10:36 +0000 <Leary> tomsmeding: https://gist.github.com/LSLeary/4c7f3ab7622d991cfa22c36efbaf0674
2026-05-28 20:09:24 +0000poscat0x04(~poscat@user/poscat) poscat
2026-05-28 20:09:18 +0000poscat(~poscat@user/poscat) (Read error: Connection reset by peer)
2026-05-28 20:07:26 +0000 <tomsmeding> can you? If you don't have value recursion, how are you going to loop?
2026-05-28 20:02:42 +0000 <mauke> can't you define 'fix' using a newtype?
2026-05-28 20:02:17 +0000Sinbad(~peter@0x5857e667-catv-dyn.rev.komnet.hu)
2026-05-28 19:45:24 +0000weary-traveler(~user@user/user363627) (Ping timeout: 244 seconds)
2026-05-28 19:43:25 +0000 <int-e> It's still relevant semantically I guess. Explains why it doesn't matter which of the mutually recursive values you evaluate first.
2026-05-28 19:42:42 +0000 <int-e> jaror: That bisection isn't attractive as an actual translation because it would duplicate computations.
2026-05-28 19:37:05 +0000 <jaror> Should be just fine even with typed Core
2026-05-28 19:36:14 +0000 <jaror> I think this is called Bekić's bisection lemma: https://en.wikipedia.org/wiki/Beki%C4%87's_theorem
2026-05-28 19:35:05 +0000 <int-e> Yeah in practice that desugaring is more about translating mutual recusion into a single fixed point. And GHC doesn't even do that; STG has a recursive let (and at the Cmm level that recusion is built into thunks with mutual references on the heap)
2026-05-28 19:33:44 +0000 <lortabac> probably impossible with a typed Core
2026-05-28 19:27:08 +0000 <int-e> lortabac: This is the hard part of the question whether `fix` and `letrec` can be defined in terms of each other.
2026-05-28 19:27:03 +0000TimWolla(~timwolla@2a01:4f8:150:6153:beef::6667) TimWolla
2026-05-28 19:26:42 +0000 <geekosaur> (and IIRC `fix` is defined in terms of `let`?)
2026-05-28 19:25:59 +0000 <geekosaur> the Haskell-level `fix` isn't, but `let` is defined as `letrec` in Haskell so must have `fix` semantics
2026-05-28 19:25:45 +0000 <lortabac> interesting
2026-05-28 19:24:46 +0000 <int-e> yes
2026-05-28 19:24:32 +0000 <lortabac> int-e: "where fix is the least fixpoint operator" -> it seems to assume that fix is a primitive
2026-05-28 19:24:27 +0000peterbecich(~Thunderbi@71.84.33.135) (Ping timeout: 265 seconds)
2026-05-28 19:22:24 +0000 <int-e> lortabac: check out the (semi-formal) translation in https://www.haskell.org/onlinereport/exps.html#sect3.12
2026-05-28 19:21:59 +0000 <c_wraith> for the purpose of being an intermediate representation... yeah, you could unify them at that point.
2026-05-28 19:21:07 +0000ouilemur(~jgmerritt@user/ouilemur) ouilemur
2026-05-28 19:20:37 +0000 <lortabac> ah ok, I see what you mean
2026-05-28 19:20:27 +0000 <lortabac> desugaring happens later
2026-05-28 19:20:26 +0000 <c_wraith> their type checking behavior is part of the semantics of the construct.
2026-05-28 19:20:04 +0000 <lortabac> I may be missing something. The typechecker knows whether it's a 'let' or a lambda and can decide whether to generalize or not
2026-05-28 19:20:00 +0000 <c_wraith> I'd argue that if you need special rules for type checking them differently, you haven't implemented one in terms of the other.
2026-05-28 19:19:52 +0000TimWolla(~timwolla@2a01:4f8:150:6153:beef::6667) (Quit: Bye)
2026-05-28 19:19:37 +0000ouilemur(~jgmerritt@user/ouilemur) (Ping timeout: 272 seconds)
2026-05-28 19:18:45 +0000 <c_wraith> the thing is, Haskell requires both of those behaviors. (as specified)
2026-05-28 19:18:27 +0000 <lambdabot> In the expression: (f 1 :: Int, f 2 :: Double)
2026-05-28 19:18:27 +0000 <lambdabot> In the expression: f 2 :: Double
2026-05-28 19:18:27 +0000 <lambdabot> Couldn't match expected type ‘Double’ with actual type ‘Int’
2026-05-28 19:18:26 +0000 <c_wraith> > (\f -> (f 1 :: Int, f 2 :: Double)) (+1)
2026-05-28 19:18:08 +0000 <lortabac> the real issue is that you need at least one of 'fix' or 'let' as a primitive
2026-05-28 19:17:43 +0000 <lortabac> this doesn't sound like a hard blocker
2026-05-28 19:17:30 +0000 <lortabac> can't you typecheck before desugaring?
2026-05-28 19:17:19 +0000 <lambdabot> (2,3.0)
2026-05-28 19:17:18 +0000 <c_wraith> > let f = (+1) in (f 1 :: Int, f 2 :: Double)