Newest at the top
| 2026-04-06 11:10:41 +0000 | <ski> | (a direct recursion would also be fine) |
| 2026-04-06 11:10:20 +0000 | <ski> | if you define the `foldr' version, i can then explain why it's better here |
| 2026-04-06 11:09:53 +0000 | <fp`> | But why would foldr be better? Since I'm iterating through the list backward, I can't even start thinking about IO actions until I know what the first thing to print is |
| 2026-04-06 11:09:22 +0000 | <ski> | and `>>=' is "bind" |
| 2026-04-06 11:09:12 +0000 | <gentauro> | (Y) |
| 2026-04-06 11:09:08 +0000 | <ski> | "then" |
| 2026-04-06 11:09:03 +0000 | <gentauro> | ski: what's the name of the `>>` operator? https://hackage-content.haskell.org/package/base-4.22.0.0/docs/Prelude.html#v:-62--62- |
| 2026-04-06 11:07:02 +0000 | <ski> | so, you can see that the accumulator keeps growing, as `foldl' continues looping through the list, requiring more and more space to be allocated |
| 2026-04-06 11:06:30 +0000 | <ski> | and only at this point can we start performing, executing, the `putChar' actions |
| 2026-04-06 11:06:15 +0000 | <ski> | = return () >> putChar 'a' >> putChar 'b' >> putChar 'c' |
| 2026-04-06 11:06:09 +0000 | <ski> | = foldl (\acc c -> acc >> putChar c) (return () >> putChar 'a' >> putChar 'b' >> putChar 'c') [] |
| 2026-04-06 11:06:02 +0000 | <ski> | = foldl (\acc c -> acc >> putChar c) (return () >> putChar 'a' >> putChar 'b') ['c'] |
| 2026-04-06 11:05:54 +0000 | <ski> | = foldl (\acc c -> acc >> putChar c) (return () >> putChar 'a') ['b','c'] |
| 2026-04-06 11:05:44 +0000 | <ski> | = foldl (\acc c -> acc >> putChar c) (return ()) ['a','b','c'] |
| 2026-04-06 11:05:27 +0000 | <ski> | putStr' ['a','b','c'] |
| 2026-04-06 11:05:21 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 272 seconds) |
| 2026-04-06 11:05:21 +0000 | <ski> | then the evaluation trace looks like |
| 2026-04-06 11:05:05 +0000 | <ski> | putStr' str = foldl (\acc c -> acc >> putChar c) (return ()) str |
| 2026-04-06 11:04:53 +0000 | <ski> | let's assume you defined |
| 2026-04-06 11:04:42 +0000 | fun-safe-math | (~fun-safe-@97.115.234.213) fun-safe-math |
| 2026-04-06 11:04:26 +0000 | <ski> | with `foldl', it *always* executes to the end (reaching the end of the list), before providing any result back to its caller. it's "bulky". so you can't start performing `IO'-sub-actions here, until you've seen the whole list |
| 2026-04-06 11:03:39 +0000 | <ski> | this is because `foldr' can be incremental (depending on the callback you pass it), can return parts of the result, piecemeal, so that you can start executing sub-actions, before you've determined all the sub-actions |
| 2026-04-06 11:02:40 +0000 | <ski> | using `foldr', you can do `putStr' in constant space. with `foldl', it's not constant space |
| 2026-04-06 11:02:31 +0000 | fun-safe-math | (~fun-safe-@97.115.234.213) () |
| 2026-04-06 11:02:03 +0000 | <fp`> | But why foldr? My understanding is that one uses foldr for its laziness, which benefits for infinitely long lists, but surely people don't want to print infinitely long strings |
| 2026-04-06 11:00:05 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-04-06 10:59:56 +0000 | <fp`> | Ah yeah |
| 2026-04-06 10:59:51 +0000 | <ski> | putChar '\n' >> putChar 'a' >> putChar 'b' >> putChar 'c' |
| 2026-04-06 10:59:32 +0000 | <ski> | that would give you |
| 2026-04-06 10:59:26 +0000 | <ski> | "I'd just initialize the acc to putChar '\n'" -- no |
| 2026-04-06 10:59:11 +0000 | <ski> | now, try to use `foldr' rather than `foldl' |
| 2026-04-06 10:59:03 +0000 | <ski> | yes, that's correct |
| 2026-04-06 10:58:18 +0000 | TimWolla | (~timwolla@2a01:4f8:150:6153:beef::6667) TimWolla |
| 2026-04-06 10:57:40 +0000 | <fp`> | And I guess if I wanted to make putStrLn', I'd just initialize the acc to putChar '\n' |
| 2026-04-06 10:56:48 +0000 | <fp`> | Ok yeah I was able to come up with this after perusing the docs of IO, so the lambda should be (\acc c -> acc >> putChar c) |
| 2026-04-06 10:50:59 +0000 | <yahb2> | ab |
| 2026-04-06 10:50:59 +0000 | <ski> | % do putChar 'a'; putChar 'b' |
| 2026-04-06 10:50:51 +0000 | <ski> | you could also use `do', if you prefer |
| 2026-04-06 10:50:40 +0000 | <ski> | so, try combining your `putChar c' with the `acc' action (representing everything you're planning to do with all the previous `Char'acters you've seen, so far, in the list), combining them with the `>>' operator |
| 2026-04-06 10:50:01 +0000 | TimWolla | (~timwolla@2a01:4f8:150:6153:beef::6667) (Quit: Bye) |
| 2026-04-06 10:49:45 +0000 | <ski> | that is a single compound action, that performs those two sub-actions, in that order, when it is executed |
| 2026-04-06 10:49:21 +0000 | <lambdabot> | IO () |
| 2026-04-06 10:49:20 +0000 | <ski> | @type putChar 'a' >> putChar 'b' |
| 2026-04-06 10:49:15 +0000 | <yahb2> | ab |
| 2026-04-06 10:49:15 +0000 | <ski> | % putChar 'a' >> putChar 'b' |
| 2026-04-06 10:49:13 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds) |
| 2026-04-06 10:49:02 +0000 | <ski> | and the `>>' operator is good for this |
| 2026-04-06 10:48:53 +0000 | <ski> | but that "queue" can just be a single, compound, `IO'-action, that contains all the `putChar' calls, in sequence |
| 2026-04-06 10:48:30 +0000 | <ski> | yes, basically |
| 2026-04-06 10:48:19 +0000 | <ski> | (of course, only if your `IO'-action is a part of a branch of execution that's activated in `main' will it be executed) |