Logs: freenode/#haskell
| 2020-09-26 14:34:24 | <Cale> | They might not be the first thing you learn about, since if you're an imperative programmer, the first thing to learn is how not to be wasteful with mutable variables :) |
| 2020-09-26 14:34:29 | <whataday> | I thought people always said IO is evil |
| 2020-09-26 14:34:33 | → | thir joins (~thir@p200300f27f0fc60094e773283d7bf825.dip0.t-ipconnect.de) |
| 2020-09-26 14:34:47 | <Cale> | It's evil in some ways, but it's also the entire point of running a program |
| 2020-09-26 14:35:38 | <whataday> | so let's save the princess a from evil IO a |
| 2020-09-26 14:36:15 | <whataday> | just kidding |
| 2020-09-26 14:36:16 | × | totallynotnate quits (~nate@125.161.70.37) (Client Quit) |
| 2020-09-26 14:36:21 | <dwts> | maerwald: hey, thanks. I used `stack new [project_name] to generate my project. This also creates a pagkage.yml. It is possible that when the course was recorded that wasn't the case or that pacakge.yml didn't cause issues |
| 2020-09-26 14:36:25 | <Cale> | If you're not, e.g. doing communication between threads, or any actual I/O, then using IORef might be ill-advised. |
| 2020-09-26 14:36:59 | → | mmohammadi9812 joins (~mmohammad@5.238.165.34) |
| 2020-09-26 14:37:32 | → | adam_wespiser joins (~adam_wesp@209.6.42.110) |
| 2020-09-26 14:38:06 | <whataday> | when we need to use the twisted Cont? |
| 2020-09-26 14:38:20 | <whataday> | for which scene? |
| 2020-09-26 14:38:25 | × | adam_wespiser quits (~adam_wesp@209.6.42.110) (Remote host closed the connection) |
| 2020-09-26 14:38:26 | <dwts> | maerwald: after removing package.yml I got better results |
| 2020-09-26 14:39:03 | × | John20 quits (~John@82.46.59.122) (Ping timeout: 260 seconds) |
| 2020-09-26 14:39:36 | <Cale> | whataday: Mostly we don't, but there are some cases where you run into a lot of functions which allocate/deallocate resources, and take a function which says what to do with the resource while it's available |
| 2020-09-26 14:40:05 | <Cale> | Mostly these functions have names like withSomething |
| 2020-09-26 14:40:09 | → | adam_wespiser joins (~adam_wesp@209.6.42.110) |
| 2020-09-26 14:40:12 | × | thir quits (~thir@p200300f27f0fc60094e773283d7bf825.dip0.t-ipconnect.de) (Ping timeout: 260 seconds) |
| 2020-09-26 14:40:16 | → | mmohammadi98128 joins (~mmohammad@5.238.165.34) |
| 2020-09-26 14:40:31 | → | snakemasterflex joins (~snakemast@213.100.206.23) |
| 2020-09-26 14:40:46 | <whataday> | but that's the coroutine scene |
| 2020-09-26 14:40:53 | → | heatsink joins (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) |
| 2020-09-26 14:40:53 | <Cale> | Cont and ContT can straighten out the situation where you're nesting a lot of such functions to allocate (and later deallocate) many resources |
| 2020-09-26 14:41:06 | <Cale> | and let you write code that looks like it just obtains things directly |
| 2020-09-26 14:41:12 | × | mmohammadi9812 quits (~mmohammad@5.238.165.34) (Read error: Connection reset by peer) |
| 2020-09-26 14:41:12 | mmohammadi98128 | is now known as mmohammadi9812 |
| 2020-09-26 14:41:25 | <Cale> | So instead of: |
| 2020-09-26 14:41:41 | <Cale> | withResource1 (\r1 -> withResource2 (\r2 -> ...)) |
| 2020-09-26 14:41:46 | <Cale> | You're writing something like |
| 2020-09-26 14:42:01 | <Cale> | do r1 <- getResource1; r2 <- getResource2; ... |
| 2020-09-26 14:42:49 | <Cale> | (typically, getResource1 = ContT withResource1) |
| 2020-09-26 14:44:19 | <Cale> | Sometimes, even if you're not going to build up the whole abstraction of using Cont or ContT, it can be helpful to have something like sequence for Cont to obtain a whole list of resources at once |
| 2020-09-26 14:44:26 | <Cale> | :t runCont . sequence . map cont |
| 2020-09-26 14:44:27 | <lambdabot> | [(a -> r) -> r] -> ([a] -> r) -> r |
| 2020-09-26 14:44:34 | × | adam_wespiser quits (~adam_wesp@209.6.42.110) (Ping timeout: 246 seconds) |
| 2020-09-26 14:45:02 | → | GyroW_ joins (~GyroW@ptr-48ujrfb8c7gfd2lu92q.18120a2.ip6.access.telenet.be) |
| 2020-09-26 14:45:03 | × | GyroW_ quits (~GyroW@ptr-48ujrfb8c7gfd2lu92q.18120a2.ip6.access.telenet.be) (Changing host) |
| 2020-09-26 14:45:03 | → | GyroW_ joins (~GyroW@unaffiliated/gyrow) |
| 2020-09-26 14:45:04 | <Cale> | This thing takes a list of resource-acquiring functions, and then produces a function which acquires a list of the resources all at once |
| 2020-09-26 14:45:04 | × | GyroW quits (~GyroW@unaffiliated/gyrow) (Ping timeout: 256 seconds) |
| 2020-09-26 14:45:27 | × | snakemasterflex quits (~snakemast@213.100.206.23) (Ping timeout: 240 seconds) |
| 2020-09-26 14:45:31 | × | heatsink quits (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) (Ping timeout: 258 seconds) |
| 2020-09-26 14:45:44 | <whataday> | a concret example? |
| 2020-09-26 14:45:57 | <whataday> | that above? |
| 2020-09-26 14:46:25 | × | sand_dull quits (~theuser@185.217.69.182) (Ping timeout: 240 seconds) |
| 2020-09-26 14:47:00 | <Cale> | https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.14.0.0/Foreign-Marshal-Array.html -- suppose you're doing FFI to some C library, and you need to allocate a bunch of arrays of various lengths, and then make sure they get deallocated afterwards |
| 2020-09-26 14:47:22 | <Cale> | allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b |
| 2020-09-26 14:48:02 | <Cale> | is a helpful thing to allocate an array of some length, giving the function a pointer to it, and then deallocating the array automatically once the action that the function produces has run |
| 2020-09-26 14:48:20 | <Cale> | (or if that action throws an exception...) |
| 2020-09-26 14:48:40 | → | sand_dull joins (~theuser@185.217.69.182) |
| 2020-09-26 14:48:41 | <maerwald> | sm[m]: how can I ignore stderr in shelltestrunner for a certain test? |
| 2020-09-26 14:48:45 | <Cale> | So, maybe we want to allocate a handful of arrays, perhaps of lengths 5, 7, and 10 |
| 2020-09-26 14:48:56 | → | josh_ joins (~josh@c-67-164-104-206.hsd1.ca.comcast.net) |
| 2020-09-26 14:49:23 | <Cale> | We could use that function above on the list map allocaArray [5,7,10] |
| 2020-09-26 14:49:31 | → | Gurkenglas joins (~Gurkengla@unaffiliated/gurkenglas) |
| 2020-09-26 14:49:38 | <Cale> | :t allocaArray -- wonder if we have this around... |
| 2020-09-26 14:49:40 | <lambdabot> | error: Variable not in scope: allocaArray |
| 2020-09-26 14:49:53 | <Cale> | :t Foreign.Marshal.Array.allocaArray -- qualified? |
| 2020-09-26 14:49:54 | <lambdabot> | Foreign.Storable.Storable a => Int -> (GHC.Ptr.Ptr a -> IO b) -> IO b |
| 2020-09-26 14:49:57 | <Cale> | cool |
| 2020-09-26 14:50:05 | <Cale> | :t map Foreign.Marshal.Array.allocaArray [5,7,10] |
| 2020-09-26 14:50:06 | <whataday> | ... |
| 2020-09-26 14:50:07 | <lambdabot> | Foreign.Storable.Storable a => [(GHC.Ptr.Ptr a -> IO b) -> IO b] |
| 2020-09-26 14:50:22 | <Cale> | :t runCont . sequence . map cont $ map Foreign.Marshal.Array.allocaArray [5,7,10] |
| 2020-09-26 14:50:24 | <lambdabot> | Foreign.Storable.Storable a => ([GHC.Ptr.Ptr a] -> IO b) -> IO b |
| 2020-09-26 14:50:38 | <Cale> | Now it's a thing which gives our function a list of pointers :) |
| 2020-09-26 14:50:52 | <Cale> | (to our arrays of size 5, 7, and 10) |
| 2020-09-26 14:51:02 | → | heatsink joins (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) |
| 2020-09-26 14:51:06 | <Cale> | and it'll deallocate all the arrays after we're done using them |
| 2020-09-26 14:51:14 | <Cale> | (once the action completes) |
| 2020-09-26 14:52:06 | <Cale> | I'm not sure I'd take the trouble of using Cont in exactly this situation, but when you end up nesting a large number of withFoo-style functions it can end up untangling code. |
| 2020-09-26 14:52:24 | × | jb55 quits (~jb55@gateway/tor-sasl/jb55) (Remote host closed the connection) |
| 2020-09-26 14:52:49 | <Cale> | Mostly, we just don't use Cont though. It's a good example monad, but it's not all that practical. Usually something with less power will do the trick. |
| 2020-09-26 14:53:03 | <whataday> | yes |
| 2020-09-26 14:53:05 | <Cale> | Cont gives you callCC which is like first-class GOTO |
| 2020-09-26 14:53:30 | <Cale> | and... usually that's just a recipe for creating headaches |
| 2020-09-26 14:53:34 | <whataday> | nesting is easy to understand |
| 2020-09-26 14:54:33 | → | jb55 joins (~jb55@gateway/tor-sasl/jb55) |
| 2020-09-26 14:54:40 | <Cale> | Yeah, though, sometimes it's awkward to write the thing which straightforwardly nests, when you don't know ahead of time which things you'll want to allocate, or there are an indefinite number of them |
| 2020-09-26 14:54:56 | <glguy> | Allocation nesting doesn't need the full Cont, at least |
| 2020-09-26 14:55:11 | <Cale> | That as well |
| 2020-09-26 14:55:27 | × | heatsink quits (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) (Ping timeout: 240 seconds) |
| 2020-09-26 14:56:06 | <whataday> | I'm glad we can do something with easy way |
| 2020-09-26 14:56:19 | <Cale> | The way I like to think about callCC is that it gives you exactly the thing that return does in C/Python/whatever |
| 2020-09-26 14:56:22 | <glguy> | https://github.com/glguy/irc-core/blob/v2/src/Client/CApi.hs#L265 |
| 2020-09-26 14:56:41 | <Cale> | Except that it gives it to you *as a function which you can pass around and call from wherever* |
| 2020-09-26 14:56:46 | <glguy> | That module needs a ton of nested with- operations |
| 2020-09-26 14:56:56 | <whataday> | call/cc is easy to use and understand in scheme |
| 2020-09-26 14:57:18 | <whataday> | if we don't to think how it's implemented |
| 2020-09-26 14:57:44 | <Cale> | For some value of "easy to understand" which allows for arbitrarily-hard-to-understand interactions |
| 2020-09-26 14:58:02 | <glguy> | Easy to know you don't understand it? |
| 2020-09-26 14:59:35 | → | Lord_of_Life_ joins (~Lord@unaffiliated/lord-of-life/x-0885362) |
| 2020-09-26 15:00:01 | × | maxfragg1 quits (~maxfragg@185.244.214.216) () |
| 2020-09-26 15:00:22 | → | alexkubicail joins (~alexkubic@37.142.205.101) |
| 2020-09-26 15:01:13 | → | heatsink joins (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) |
| 2020-09-26 15:01:14 | × | Lord_of_Life quits (~Lord@unaffiliated/lord-of-life/x-0885362) (Ping timeout: 272 seconds) |
| 2020-09-26 15:02:29 | Lord_of_Life_ | is now known as Lord_of_Life |
| 2020-09-26 15:02:49 | × | coot quits (~coot@37.30.52.6.nat.umts.dynamic.t-mobile.pl) (Quit: coot) |
All times are in UTC.