Home liberachat/#haskell: Logs Calendar

Logs: liberachat/#haskell

←Prev  Next→ 1,789,380 events total
2026-04-06 11:20:51 <ski> or, if you prefer
2026-04-06 11:20:54 <ski> putStr' (c:cs) = do putChar c; putStr' cs
2026-04-06 11:20:59 <ski> for the last defining equation
2026-04-06 11:21:11 <ski> then basically the same thing would happen, as in the `foldr' version
2026-04-06 11:21:38 <ski> (this is the "direct recursive" version)
2026-04-06 11:22:03 __monty__ joins (~toonn@user/toonn)
2026-04-06 11:22:33 xff0x joins (~xff0x@2405:6580:b080:900:388f:e7ec:f5bb:9bd0)
2026-04-06 11:22:39 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 255 seconds)
2026-04-06 11:25:25 <ski> both `foldl' and `foldr' start "from the left". what differs is the way it "associates" the callback (to the left, like `((z - a) - b) - c', for `foldl (-) z [a,b,c]', vs. to the right, like `a - (b - (c - z))', for `foldr (-) z [a,b,c]'). `foldl' keeps adding to, growing, the accumulator, while `foldr' wraps its recursive calls inside calls to the callback
2026-04-06 11:25:39 <ski> > foldl f z [a,b,c] :: Expr
2026-04-06 11:25:40 <lambdabot> f (f (f z a) b) c
2026-04-06 11:25:42 <ski> > foldr f z [a,b,c] :: Expr
2026-04-06 11:25:44 <lambdabot> f a (f b (f c z))
2026-04-06 11:26:25 <ski> `foldr' hands over control to the callback, and lets it decide if and when to continue with the `foldr' recursive call (being the second parameter passed to the callback)
2026-04-06 11:26:50 <ski> `foldl' keeps control, until it reaches the end of the list
2026-04-06 11:28:21 <ski> > foldr (||) False (map (> 10) [0 ..]) -- this hands over control to `||', which decides whether to continye with the next recursive `foldr' call or not
2026-04-06 11:28:22 <lambdabot> True
2026-04-06 11:28:41 <fp`> So foldr looks something like this (with an additional boundary condition)
2026-04-06 11:28:42 <fp`> foldr f acc x:xs = (f x acc) : (foldr f acc xs)
2026-04-06 11:29:38 <fp`> and the short-circuiting logic is down to... the implementor of (||)? Or ghc? Or is there even a runtime component?
2026-04-06 11:33:26 × tromp quits (~textual@2001:1c00:340e:2700:795f:6a6f:7cb5:ecd6) (Quit: My iMac has gone to sleep. ZZZzzz…)
2026-04-06 11:33:41 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 11:33:44 <ski> not quite that
2026-04-06 11:33:54 <ski> there is no `:' is the result of `foldr'
2026-04-06 11:34:22 <ski> but yes, the implementor of `||' (or whichever callback you're using)
2026-04-06 11:34:26 <ski> @src (||)
2026-04-06 11:34:27 <lambdabot> True || _ = True
2026-04-06 11:34:27 <lambdabot> False || x = x
2026-04-06 11:34:43 <ski> that short-circuits, does not evaluate the right parameter, in case the left is `True'
2026-04-06 11:39:03 <fp`> So the `_' is what causes the short circuiting?
2026-04-06 11:39:19 <ski> the short-circuiting is not built-in, is just a consequence of how `||' is defined, and how lazy evaluation works
2026-04-06 11:39:24 <ski> yes, in this case
2026-04-06 11:39:27 <ski> but if it had said
2026-04-06 11:39:33 <ski> True || x = True
2026-04-06 11:39:42 <ski> it would also have ignored `x', still short-circuiting
2026-04-06 11:40:03 <ski> what matters is whether the parameter is used/demanded/forced, not really whether it's named
2026-04-06 11:40:34 <fp`> I see
2026-04-06 11:40:45 <ski> of course, if it's not named, then you're not forcing it (unless you use a strictness annotation, e.g. `!_'), so it's not forced unless someone else is forcing it, elsewhere
2026-04-06 11:41:43 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 264 seconds)
2026-04-06 11:41:46 <ski> (you could pass the same list to two different places. one might use `_' (not forcing), while the other might force it, naming)
2026-04-06 11:44:28 × TimWolla quits (~timwolla@2a01:4f8:150:6153:beef::6667) (Quit: Bye)
2026-04-06 11:45:08 <fp`> Also, where does lambdabot's Expr type come from? That would be quite useful to me
2026-04-06 11:45:16 <ski> @src any
2026-04-06 11:45:16 <lambdabot> any p = or . map p
2026-04-06 11:45:17 <ski> @src or
2026-04-06 11:45:17 <lambdabot> or = foldr (||) False
2026-04-06 11:45:27 merijn joins (~merijn@62.45.136.136)
2026-04-06 11:45:32 <ski> so, the example above is the same as `any (> 10) [0 ..]'
2026-04-06 11:47:09 <ski> @hackage simple-reflect
2026-04-06 11:47:09 <lambdabot> https://hackage.haskell.org/package/simple-reflect
2026-04-06 11:47:12 <ski> fp` ^
2026-04-06 11:50:54 <fp`> Cool. Thank you so much for all the help!
2026-04-06 11:51:36 <ski> np
2026-04-06 11:52:09 × merijn quits (~merijn@62.45.136.136) (Ping timeout: 248 seconds)
2026-04-06 11:57:16 TimWolla joins (~timwolla@2a01:4f8:150:6153:beef::6667)
2026-04-06 12:01:21 × craunts795335385 quits (~craunts@152.32.99.2) (Quit: The Lounge - https://thelounge.chat)
2026-04-06 12:02:34 × TimWolla quits (~timwolla@2a01:4f8:150:6153:beef::6667) (Remote host closed the connection)
2026-04-06 12:03:21 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 12:08:29 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 252 seconds)
2026-04-06 12:08:48 TimWolla joins (~timwolla@2a01:4f8:150:6153:beef::6667)
2026-04-06 12:10:08 raelie joins (~raelie@user/raelie)
2026-04-06 12:13:33 craunts795335385 joins (~craunts@152.32.99.2)
2026-04-06 12:14:46 × Pozyomka quits (~pyon@user/pyon) (Quit: brb)
2026-04-06 12:19:08 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 12:24:01 × m quits (~travltux@user/travltux) (Quit: WeeChat 4.7.2)
2026-04-06 12:24:28 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 256 seconds)
2026-04-06 12:26:35 m2 joins (~travltux@user/travltux)
2026-04-06 12:35:11 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 12:39:43 Pozyomka joins (~pyon@user/pyon)
2026-04-06 12:40:10 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 245 seconds)
2026-04-06 12:40:31 × chromoblob quits (~chromoblo@user/chromob1ot1c) (Ping timeout: 264 seconds)
2026-04-06 12:43:56 sonny joins (~sonny@bras-base-london140cw-grc-17-142-113-177-150.dsl.bell.ca)
2026-04-06 12:44:37 Pixi` is now known as Pixi
2026-04-06 12:44:51 × rainbyte quits (~rainbyte@181.47.219.3) (Read error: Connection reset by peer)
2026-04-06 12:45:42 rainbyte joins (~rainbyte@181.47.219.3)
2026-04-06 12:46:20 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 12:47:30 × Lord_of_Life quits (~Lord@user/lord-of-life/x-2819915) (Excess Flood)
2026-04-06 12:48:53 Lord_of_Life joins (~Lord@user/lord-of-life/x-2819915)
2026-04-06 12:50:25 tromp joins (~textual@2001:1c00:340e:2700:8cf8:7bb7:a0e:7cfa)
2026-04-06 12:51:30 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds)
2026-04-06 12:59:08 × oats quits (~oats@user/oats) (Read error: Connection reset by peer)
2026-04-06 12:59:22 oats joins (~oats@user/oats)
2026-04-06 13:02:09 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 13:05:30 <fp`> So in the sense that `putChar 'c'` is evaluated to <IO action> and that is eventually executed to produce a 'c' in the tty, who does the executing? Is this a metaphor for how GHC produces code, or is there a runtime that is literally turning IO actions into syscalls?
2026-04-06 13:06:26 × tromp quits (~textual@2001:1c00:340e:2700:8cf8:7bb7:a0e:7cfa) (Quit: My iMac has gone to sleep. ZZZzzz…)
2026-04-06 13:07:31 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 264 seconds)
2026-04-06 13:11:30 <probie> fp`: Something of type `IO a` is modelled by GHC as function from the current state of the universe, to a pair containing the new state of the universe, and a value of type `a`. As part of generating this "new state of the universe", IO actions happen
2026-04-06 13:14:37 <probie> e.g. something of type `Char -> IO ()` is really `Char -> Universe -> ((), Universe)`, and the interface of the IO monad prevents you from using that `Universe` twice. In reality it's actually `Char -> State# RealWorld -> (# State# RealWorld, a #)`
2026-04-06 13:16:44 <probie> `State# RealWorld` is a special 0-bit type that's just a token (since you can't actually pass the universe around), and the `(# ..., ... #)` is an "unboxed tuple", which you can think of as a strict tuple with no runtime overhead
2026-04-06 13:17:51 merijn joins (~merijn@host-cl.cgnat-g.v4.dfn.nl)
2026-04-06 13:23:17 × merijn quits (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 252 seconds)
2026-04-06 13:25:01 Square2 joins (~Square@user/square)
2026-04-06 13:25:04 <ski> fp` : yes, you can think of it as a run-time that interprets the `IO'-action values, actually performing them
2026-04-06 13:25:52 <ski> (for efficiency, it does get compiled, by GHC, to code that directly performs the indicated actions, rather than interpreting data structures)
2026-04-06 13:26:31 <ski> if you want to, you could imagine a data type something like
2026-04-06 13:26:56 <ski> data MyIO :: * -> *
2026-04-06 13:26:58 <ski> where
2026-04-06 13:27:04 <ski> Return :: a -> MyIO a
2026-04-06 13:27:17 <ski> Bind :: MyIO a -> (a -> MyIO b) -> MyIO b
2026-04-06 13:27:38 <ski> OpenFile :: FilePath -> IOMode -> MyIO Handle

All times are in UTC.