Logs: freenode/#haskell
| 2020-09-26 14:02:32 | <Cale> | Well, let's look at the type first of all |
| 2020-09-26 14:02:43 | <Cale> | Cont r a -> (a -> Cont r b) -> Cont r b |
| 2020-09-26 14:03:19 | <Cale> | So that's like ((a -> r) -> r) -> (a -> ((b -> r) -> r)) -> ((b -> r) -> r) |
| 2020-09-26 14:03:57 | <Cale> | It's a bit of a puzzle figuring out how to put these pieces together, but there's not all that many ways to do it |
| 2020-09-26 14:04:04 | <whataday> | construct a new Cont, and the value is from the second parameter |
| 2020-09-26 14:04:27 | × | heatsink quits (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) (Ping timeout: 240 seconds) |
| 2020-09-26 14:05:22 | <Cale> | It's sort of a funny thing, Cont r a is like a thing which can answer r-valued questions that are presumably about a value of type a. However there might not actually be a value of type a for which the answers it gives are the right ones. |
| 2020-09-26 14:05:23 | <whataday> | use function a-> Cont r b to construct a new Cont with a from Cont r a? |
| 2020-09-26 14:05:43 | × | merijn quits (~merijn@83-160-49-249.ip.xs4all.nl) (Ping timeout: 246 seconds) |
| 2020-09-26 14:06:12 | <Cale> | But yeah, the general way of things is that x >>= f is going to "run x" (whatever that means) and then apply f to its result to figure out what to run after that |
| 2020-09-26 14:07:13 | <Cale> | In the case of Cont specifically, it can be a bit tricky to think through what's going on, though we can have a machine do it for us if we like: |
| 2020-09-26 14:07:20 | <Cale> | @djinn ((a -> r) -> r) -> (a -> ((b -> r) -> r)) -> ((b -> r) -> r) |
| 2020-09-26 14:07:20 | <lambdabot> | f a b c = a (\ d -> b d c) |
| 2020-09-26 14:09:10 | <Cale> | Actually, let me rephrase this a bit so that it makes more sense... |
| 2020-09-26 14:09:18 | × | utopic_int0x80 quits (~lucid_0x8@188.253.232.227) (Ping timeout: 256 seconds) |
| 2020-09-26 14:09:41 | <whataday> | we give an unary function to Cont r a to extract a, then pass a to a-> Cont r b to construct Cont r b? |
| 2020-09-26 14:09:56 | <Cale> | Yeah, d :: a here |
| 2020-09-26 14:10:39 | → | heatsink joins (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) |
| 2020-09-26 14:10:42 | <Cale> | So it's like we're making a thing which can answer questions (which djinn called c) about a value of type b |
| 2020-09-26 14:11:47 | <Cale> | and we do it by asking the Cont r a the question "if we applied this function of type (a -> Cont r b) to your value of type a, and then asked the resulting Cont r b our question, what would its answer be?" |
| 2020-09-26 14:12:22 | × | snakemasterflex quits (~snakemast@213.100.206.23) (Ping timeout: 246 seconds) |
| 2020-09-26 14:14:08 | <whataday> | wait a sec, we extract Cont r a by passing (a->r), and a is passing to a-> Cont r b too |
| 2020-09-26 14:14:17 | <Cale> | newtype QuestionBox r a = Box { askTheBox :: (a -> r) -> r } |
| 2020-09-26 14:14:58 | × | heatsink quits (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) (Ping timeout: 256 seconds) |
| 2020-09-26 14:15:11 | <Cale> | x >>= f = Box (\question -> askTheBox x (\a -> askTheBox (f a) question)) |
| 2020-09-26 14:15:28 | → | machinedgod joins (~machinedg@bras-base-sconpq1802w-grc-02-69-159-109-171.dsl.bell.ca) |
| 2020-09-26 14:15:31 | <whataday> | QuestionBlx r a = Box (a-> r) -> r |
| 2020-09-26 14:16:01 | <whataday> | askTheBox QuestionBox r a :: (a->r)->r |
| 2020-09-26 14:16:34 | <Cale> | askTheBox's full type here would be askTheBox :: QuestionBox r a -> (a -> r) -> r |
| 2020-09-26 14:16:41 | <whataday> | askTheBox and Box are isomorphic |
| 2020-09-26 14:17:05 | <Cale> | No, but they're isomorphisms in opposite directions between QuestionBox r a and (a -> r) -> r |
| 2020-09-26 14:17:31 | <whataday> | oh right |
| 2020-09-26 14:17:37 | <Cale> | Box :: ((a -> r) -> r) -> QuestionBox r a |
| 2020-09-26 14:17:49 | <Cale> | askTheBox :: QuestionBox r a -> ((a -> r) -> r) |
| 2020-09-26 14:18:09 | <whataday> | Box (a->r) ->r :: QuestionBox r a |
| 2020-09-26 14:18:26 | × | random quits (~random@185.219.70.106) (Ping timeout: 256 seconds) |
| 2020-09-26 14:18:37 | <Cale> | Or it would be more correct to say that when f :: (a -> r) -> r, then Box f :: QuestionBox r a |
| 2020-09-26 14:18:47 | <whataday> | I don't understand why haskell always wrap them? |
| 2020-09-26 14:18:54 | <Cale> | wrap what? |
| 2020-09-26 14:19:03 | <whataday> | the type the value |
| 2020-09-26 14:19:08 | <Cale> | hm? |
| 2020-09-26 14:19:24 | <whataday> | Box (a->r)->r |
| 2020-09-26 14:19:44 | <Cale> | That's mixing up things at the term and type level |
| 2020-09-26 14:19:55 | <Cale> | Box is a term, it lives on the left side of the :: |
| 2020-09-26 14:19:56 | <whataday> | why not just use function to express |
| 2020-09-26 14:20:01 | <Cale> | (a -> r) -> r is a type |
| 2020-09-26 14:20:07 | <Cale> | it lives on the right side of the :: |
| 2020-09-26 14:20:45 | → | heatsink joins (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) |
| 2020-09-26 14:21:09 | <Cale> | As for why we don't just work with functions here |
| 2020-09-26 14:21:17 | <Cale> | Well, it's a few different reasons |
| 2020-09-26 14:21:35 | <Cale> | One is that we're trying to produce an abstraction, functions are just our implementation mechanism |
| 2020-09-26 14:21:48 | <whataday> | for Reader, a->r is a type, why we use Reader r a to express it? |
| 2020-09-26 14:21:53 | <Cale> | Eventually, we'll have enough pieces that perhaps we won't need to use Box explicitly so much |
| 2020-09-26 14:22:02 | <Cale> | Similarly with Reader |
| 2020-09-26 14:22:24 | <Cale> | Secondly, we can't have more than one instance of Monad for functions |
| 2020-09-26 14:22:36 | <Cale> | and the Reader-like instance is already there |
| 2020-09-26 14:23:09 | <Cale> | (and the Cont-like one wouldn't really work, since we can't isolate the appropriate type parameter in a points-free way) |
| 2020-09-26 14:23:15 | → | totallynotnate joins (~nate@125.161.70.37) |
| 2020-09-26 14:23:59 | <Cale> | In order to have a monad, we need a type level function M such that our computations have types that look like M a |
| 2020-09-26 14:24:17 | <whataday> | not all languages support higher-kinded polymorphism, here we use Reader r a to express is not available in other languages |
| 2020-09-26 14:24:18 | <Cale> | So Cont r does that for us here |
| 2020-09-26 14:24:27 | × | TooDifficult quits (~TooDiffic@139.59.59.230) (Quit: TooDifficult) |
| 2020-09-26 14:24:38 | <Cale> | Or Reader r |
| 2020-09-26 14:24:50 | <Cale> | instance Monad (Reader r) where ... |
| 2020-09-26 14:24:59 | <Cale> | It turns out we *can* write: |
| 2020-09-26 14:25:06 | <Cale> | instance Monad ((->) r) where ... |
| 2020-09-26 14:25:10 | × | heatsink quits (~heatsink@107-136-5-69.lightspeed.sntcca.sbcglobal.net) (Ping timeout: 256 seconds) |
| 2020-09-26 14:25:16 | <Cale> | partially-applying the function arrow |
| 2020-09-26 14:25:48 | <whataday> | r-> is the monad for Reader |
| 2020-09-26 14:25:51 | <Cale> | But (1) that's a little sneaky and might even be considered a little too surprising |
| 2020-09-26 14:25:56 | <Cale> | and (2) it doesn't work for Cont |
| 2020-09-26 14:26:15 | <whataday> | (a->r)-> ? |
| 2020-09-26 14:26:24 | <whataday> | can't be monad for cont? |
| 2020-09-26 14:26:31 | <Cale> | Yeah, we need an M for which M a = (a -> r) -> r |
| 2020-09-26 14:26:43 | <Cale> | and we can't get that by partial application of anything which already exists |
| 2020-09-26 14:27:58 | <whataday> | some people are familiar with continuation or cps in other languages, but in haskell, cont monad is hard to understand by type signature |
| 2020-09-26 14:28:15 | <whataday> | other I mean dynamic languages |
| 2020-09-26 14:28:19 | × | GyroW quits (~GyroW@unaffiliated/gyrow) (Quit: Someone ate my pie) |
| 2020-09-26 14:28:36 | → | GyroW joins (~GyroW@d54C03E98.access.telenet.be) |
| 2020-09-26 14:28:36 | × | GyroW quits (~GyroW@d54C03E98.access.telenet.be) (Changing host) |
| 2020-09-26 14:28:36 | → | GyroW joins (~GyroW@unaffiliated/gyrow) |
| 2020-09-26 14:29:08 | <Cale> | It's not really any worse than understanding continuations in other dynamic languages, I think. It's just that what you need to understand has been made explicit by the types |
| 2020-09-26 14:29:58 | <Cale> | Continuations are a little bit twisty and confusing in either case, but without types, you *really* have to know what you're doing |
| 2020-09-26 14:30:32 | → | mananamenos joins (~mananamen@84.122.202.215.dyn.user.ono.com) |
| 2020-09-26 14:30:57 | <whataday> | just like closure in dynamic languages, easy to understand and use, but in haskell I don't understand how to |
| 2020-09-26 14:31:17 | <Cale> | Closures are just an implementation mechanism for functions |
| 2020-09-26 14:31:37 | <whataday> | in dynamic languages we can change variables in an environment, but haskell can't change |
| 2020-09-26 14:31:43 | <Cale> | In Haskell, we usually just say "function" and not "closure" unless we're really talking about the low-level implementation |
| 2020-09-26 14:31:45 | → | merijn joins (~merijn@83-160-49-249.ip.xs4all.nl) |
| 2020-09-26 14:32:04 | → | turion joins (~turion@ip5f5af77e.dynamic.kabel-deutschland.de) |
| 2020-09-26 14:32:28 | <Cale> | You can define things which capture mutable variables from their scope of definition in Haskell if you like |
| 2020-09-26 14:32:31 | <solonarv> | you absolutely can have mutable references in Haskell, and you can have functions that close over them |
| 2020-09-26 14:32:39 | <solonarv> | heh, ninja'd |
| 2020-09-26 14:32:55 | <Cale> | Make a new IORef and return a function which produces an action that writes to it, and separately an action which reads from it |
| 2020-09-26 14:33:23 | <whataday> | but IORef is not suggested |
| 2020-09-26 14:33:28 | <Cale> | ? |
| 2020-09-26 14:33:33 | × | totallynotnate quits (~nate@125.161.70.37) (Quit: WeeChat 2.9) |
| 2020-09-26 14:33:43 | <Cale> | IORefs definitely have their place |
| 2020-09-26 14:33:49 | × | mmohammadi9812 quits (~mmohammad@5.238.165.34) (Ping timeout: 264 seconds) |
| 2020-09-26 14:34:16 | → | totallynotnate joins (~nate@125.161.70.37) |
All times are in UTC.