Home freenode/#haskell: Logs Calendar

Logs: freenode/#haskell

←Prev  Next→
Page 1 .. 226 227 228 229 230 231 232 233 234 235 236 .. 5022
502,152 events total
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.