Home liberachat/#haskell: Logs Calendar

Logs: liberachat/#haskell

←Prev  Next→ 1,803,913 events total
2021-07-31 14:24:46 <phaazon> Guest1599: c is a constraint that will be applied on a functor wrapped in an existential
2021-07-31 14:25:15 <phaazon> so I guess you’d use that with Task MonadIO to get a task running in « a MonadIO »
2021-07-31 14:26:46 × jneira_ quits (~jneira_@28.red-80-28-169.staticip.rima-tde.net) (Ping timeout: 272 seconds)
2021-07-31 14:26:52 wroathe joins (~wroathe@c-68-54-25-135.hsd1.mn.comcast.net)
2021-07-31 14:28:40 × cheater quits (~Username@user/cheater) (Ping timeout: 272 seconds)
2021-07-31 14:29:56 × xff0x quits (~xff0x@2001:1a81:536d:8c00:2d4:a9e1:415e:5f77) (Ping timeout: 256 seconds)
2021-07-31 14:30:16 <[exa]> phaazon: the all-to-all conversions don't really work nice with type inference, you'll usually jump into a situation where the type system needs to do a DFS on your code to find a good variant (and finish it to prove that it's not ambiguous), which is far from having the types intuitive
2021-07-31 14:30:34 × fossdd quits (~fossdd@sourcehut/user/fossdd) (Ping timeout: 240 seconds)
2021-07-31 14:30:41 <Guest1599> phaazon I'm a Haskell beginner; I know how to read `newtype ZipList a = ZipList { getZipList :: [a] }` and how to construct a type out of it (i.e. `ZipList Int`)
2021-07-31 14:30:54 <Guest1599> but this `Task` still looks vague to me
2021-07-31 14:30:58 fossdd joins (~fossdd@sourcehut/user/fossdd)
2021-07-31 14:31:17 <phaazon> [exa]: you mean because of the two type variables?
2021-07-31 14:31:38 Atum_ joins (~IRC@user/atum/x-2392232)
2021-07-31 14:31:39 <phaazon> yeah, well, I agree it’s not perfect but most of the time it works great (in Rust at least, and Haskell type system is far better so I would expect it to behave better :D)
2021-07-31 14:31:55 <phaazon> Guest1599: what’s bothering you is the forall, right?
2021-07-31 14:32:10 <phaazon> you might need to get a look at a more specific version
2021-07-31 14:32:12 <phaazon> like TaskIO
2021-07-31 14:32:25 <[exa]> in rust the contexts are much much smaller, so it usually works nicely
2021-07-31 14:32:47 <[exa]> in haskell you can easily get a function that has a whole convert chain in the type signature
2021-07-31 14:32:48 <phaazon> newtype TaskIO k v = TaskIO (forall f. MonadIO f => (k -> f v) -> f v) -- Guest1599
2021-07-31 14:33:26 <phaazon> Guest1599: the forall here means that you cannot inspect and know what f it’s being used
2021-07-31 14:33:39 <phaazon> the only place where you know that information is prior wrapping that function in the TaskIO
2021-07-31 14:33:46 <phaazon> once it’s wrapped in, you lose the information of the type of f
2021-07-31 14:33:54 <phaazon> and you only know about the constraint
2021-07-31 14:34:03 <phaazon> so basically, MonadIO f, but you can’t know what f is inside
2021-07-31 14:34:29 <Guest1599> hmm, okay
2021-07-31 14:34:36 <phaazon> so you pass a (k -> f v) function and you get back a f v
2021-07-31 14:34:58 <phaazon> I don’t know what that k and v means but it’s very likely to be an environment pattern, or some kind of pointer you can lookup in MonadIO
2021-07-31 14:35:13 <phaazon> now, your initial type sig also abstracted on the constraint
2021-07-31 14:35:18 <Guest1599> k - `key`, v - `value`, think of it as a storage
2021-07-31 14:35:21 <phaazon> (with the c type param)
2021-07-31 14:35:26 <phaazon> yeah that makes sense
2021-07-31 14:36:24 <Guest1599> " pass a (k -> f v) function and you get back a f v" - where to pass it? I'm a bit lost
2021-07-31 14:36:52 AlexNoo_ is now known as AlexNoo
2021-07-31 14:37:09 <Guest1599> i.e. with `Maybe`: it's a type constructor - one can pass a type and it becomes `Maybe PassedType` - a concrete type
2021-07-31 14:37:21 <Guest1599> I see thath TaskIO also accepts two types - `k` and `v`
2021-07-31 14:37:39 <Guest1599> so... where's the place for `k -> f v` herE?
2021-07-31 14:38:41 jakalx joins (~jakalx@base.jakalx.net)
2021-07-31 14:40:02 <Guest1599> I think my problem is that the right-hand side of `=` looks like nothing I've seen in the context of a newtype
2021-07-31 14:40:51 <phaazon> Guest1599: yeah you’d have to pattern match on it
2021-07-31 14:40:58 <phaazon> or use a function that does that for you
2021-07-31 14:41:16 <phaazon> rewritting TaskIO in a way that automatically provides you a nice function to do so:
2021-07-31 14:41:22 <Guest1599> I think I'm more lost than you expect
2021-07-31 14:41:36 <phaazon> newtype TaskIO k v = TaskIO { runTaskIO :: forall f. MonadIO f => (k -> f v) -> f v }
2021-07-31 14:42:58 × fossdd quits (~fossdd@sourcehut/user/fossdd) (Ping timeout: 240 seconds)
2021-07-31 14:43:16 fossdd joins (~fossdd@sourcehut/user/fossdd)
2021-07-31 14:43:32 kuribas joins (~user@ptr-25vy0i7fhp3jdg2nokv.18120a2.ip6.access.telenet.be)
2021-07-31 14:43:53 <Guest1599> runTaskIO someTaskIO kToFVfunction would return `f v`...?
2021-07-31 14:44:02 <phaazon> I can give you an example, wait :)
2021-07-31 14:44:58 <Guest1599> phaazon : if it helps, the line comes from https://www.cambridge.org/core/journals/journal-of-functional-programming/article/build-systems-a-la-carte-theory-and-practice/097CE52C750E69BD16B78C318754C7A4 page 9
2021-07-31 14:45:36 <Guest1599> (the Task is a custom one, seperated from stdlib etc)
2021-07-31 14:46:22 <phaazon> so:
2021-07-31 14:46:34 <phaazon> let task = TaskIO $ \lookup -> liftA2 (+) (lookup "hey") (lookup "you")
2021-07-31 14:46:53 <phaazon> here, we just lookup two keys (setting k = String)
2021-07-31 14:46:57 <phaazon> and we add them together
2021-07-31 14:47:09 slowButPresent joins (~slowButPr@user/slowbutpresent)
2021-07-31 14:47:09 <phaazon> so that we have v as Num v
2021-07-31 14:47:27 <phaazon> the type of task is then (Num v) => TakIO String v
2021-07-31 14:47:27 × MQ-17J quits (~MQ-17J@d14-69-206-129.try.wideopenwest.com) (Read error: Connection reset by peer)
2021-07-31 14:47:44 <phaazon> now, you need to run that task, so as I told you earlier, you need to pass that (k -> f v) function
2021-07-31 14:47:52 <phaazon> let’s just mockup something really quick
2021-07-31 14:48:01 <phaazon> lookup "hey" = pure 1; lookup "you" = pure 2; lookup _ = pure 0
2021-07-31 14:48:05 MQ-17J joins (~MQ-17J@d14-69-206-129.try.wideopenwest.com)
2021-07-31 14:48:10 <phaazon> running the task like:
2021-07-31 14:48:17 <phaazon> runTaskIO task lookup
2021-07-31 14:48:23 × MQ-17J quits (~MQ-17J@d14-69-206-129.try.wideopenwest.com) (Read error: Connection reset by peer)
2021-07-31 14:48:25 <phaazon> will tie everything and will provide 3
2021-07-31 14:49:03 <phaazon> the only place where we know the type of f is when we define task
2021-07-31 14:49:19 <phaazon> I didn’t do anything specific but I could have used liftIO . print and it would have made f = IO
2021-07-31 14:49:33 MQ-17J joins (~MQ-17J@d14-69-206-129.try.wideopenwest.com)
2021-07-31 14:50:05 <phaazon> the important thing is that you will get back a value in f v, yes
2021-07-31 14:50:29 lbseale joins (~lbseale@user/ep1ctetus)
2021-07-31 14:51:19 <Guest1599> (let me digest it)
2021-07-31 14:51:27 <phaazon> sure
2021-07-31 14:51:36 <phaazon> existential quantification is not really beginner level anyway :)
2021-07-31 14:51:44 <phaazon> it’s completly normal if you feel overwhelmed by it
2021-07-31 14:52:17 xff0x joins (~xff0x@2001:1a81:536d:8c00:2d4:a9e1:415e:5f77)
2021-07-31 14:52:22 <Guest1599> First qustion: Why `newtype TaskIO k v = TaskIO { runTaskIO :: forall f. MonadIO f => (k -> f v) -> f v} ` , not just `newtype TaskIO k v = TaskIO { runTaskIO :: (MonadIO f) => (k -> f v) -> f v } ` ?
2021-07-31 14:53:00 <Guest1599> what would be the difference?
2021-07-31 14:53:09 <phaazon> good question; the right side of a data type declaration must use either concrete types or type variables declared on the left part
2021-07-31 14:53:23 <phaazon> f here is only known on the right side
2021-07-31 14:53:31 <phaazon> it doesn’t appear on the left side
2021-07-31 14:53:37 <phaazon> so if I give you two different tasks
2021-07-31 14:53:58 <phaazon> which types are TaskIO Int String and TaskIO Int String, what f is inside of them? the same? different? :)
2021-07-31 14:54:17 nate3 joins (~nate@108-233-125-227.lightspeed.sntcca.sbcglobal.net)
2021-07-31 14:54:29 <phaazon> so the forall keyword is a bit confusing but allows us to say “there’s a f inside of that thing and it’s introduced here as existential; we know it’s there but we can’t inspect / observe it from outside”
2021-07-31 14:55:07 <Guest1599> hmmm, okay
2021-07-31 14:55:08 <phaazon> your second form would be valid if you had newtype TaskIO k f v, for instance
2021-07-31 14:55:22 × fossdd quits (~fossdd@sourcehut/user/fossdd) (Ping timeout: 240 seconds)
2021-07-31 14:55:29 <phaazon> it would be a problem, though
2021-07-31 14:55:33 fossdd joins (~fossdd@sourcehut/user/fossdd)
2021-07-31 14:55:35 <phaazon> because someone could use any functor / monad here
2021-07-31 14:55:41 <phaazon> (not necessarily MonadIO)
2021-07-31 14:56:28 <Guest1599> phaazon couldn't we provide something like `(MondaIO f) =>` on the RHS ( right-hand side of the equation sign)?
2021-07-31 14:58:08 <Guest1599> maybe that's a question that won't get us (me) anywhere though;
2021-07-31 14:58:29 <phaazon> there are different position where we can do that but yeah, not sure
2021-07-31 15:02:14 × nate3 quits (~nate@108-233-125-227.lightspeed.sntcca.sbcglobal.net) (Ping timeout: 272 seconds)
2021-07-31 15:04:50 <Guest1599> phaazon are you a regular member of this channel? (I think I need to digest what you've said, read a few more things and perhaps (tomorrow...? some time in the future) discuss further if needed. Would be nice to see you around
2021-07-31 15:09:33 bitdex joins (~bitdex@gateway/tor-sasl/bitdex)
2021-07-31 15:10:01 hnOsmium0001 joins (uid453710@id-453710.stonehaven.irccloud.com)

All times are in UTC.