Logs: freenode/#haskell
| 2021-03-21 17:52:33 | <ski> | wouldn't the only way for that operation to access the environment, in a way that relevantly depends on those constraints, be via the overloaded class methods, not using `lift' and the like to select ? |
| 2021-03-21 17:52:36 | <carter> | and thats actually *missing* the real power of monad transformers |
| 2021-03-21 17:52:41 | <dolio> | The way type classes work, they best match having a unique instance of each 'effect' for a particular `m`, and other possible instances are rendered invisible. |
| 2021-03-21 17:52:42 | <edmundnoble> | Uh yeah >>= and the algebras etc |
| 2021-03-21 17:53:03 | → | plutoniix joins (~q@ppp-27-55-75-62.revip3.asianet.co.th) |
| 2021-03-21 17:53:08 | <carter> | in any real library, you should have a concrete "core " stack thats actually known and fixed, and just some helpers for allowing new user monad stacks to also work |
| 2021-03-21 17:53:14 | <carter> | name and tame the power |
| 2021-03-21 17:53:17 | <carter> | with a newtype |
| 2021-03-21 17:54:02 | <carter> | like, a lot of peoples mains with transformer stacks would be solved if they choose a specifc one for their application, new type it |
| 2021-03-21 17:54:08 | <carter> | and give it the interfaces/instances they need |
| 2021-03-21 17:54:11 | <carter> | and then they default to using that |
| 2021-03-21 17:54:18 | <carter> | (also their code would be faster and type inference better) |
| 2021-03-21 17:54:32 | <ski> | carter : not necessarily presuming they commute (although prople probably often expect that, in some way, without reflecting upon it). but leaving the ordering up to the caller may not be what one intended, possibly leaking implementation details, or breaking invariants, preconditions & postconditions |
| 2021-03-21 17:54:41 | <chisui> | rybern: You could also create a container product type that contains all these values. Alternatively you could create your own classes that provide access to these values like `HasInt a, MonadReader a m` |
| 2021-03-21 17:54:43 | <carter> | yeah |
| 2021-03-21 17:54:50 | <carter> | ski: , yeah |
| 2021-03-21 17:54:54 | <dolio> | ski: Yeah, in effect systems that allow multiple copies of an effect to be in play (e.g. Koka), the effects are not completely reorderable, so you can sort of abstractly specify which to use. |
| 2021-03-21 17:54:58 | <carter> | hence they should always newtype and make a fresh one |
| 2021-03-21 17:55:11 | <dolio> | But type classes aren't like that. |
| 2021-03-21 17:55:17 | ski | nods |
| 2021-03-21 17:55:21 | <carter> | oh that reminds me, no one actually has a sane store for commuting effects |
| 2021-03-21 17:55:26 | <carter> | they just say "there should be one" |
| 2021-03-21 17:55:26 | ski | probably needs to look at Koka some time |
| 2021-03-21 17:55:26 | <monochrom> | "(MonadReader Int m, MonadReader String m) =>" is the product of an XY problem. A direct X solution is "(ReadTime m, HasTitle m) =>", and you tailor-design the ReadTime class and the HasTitle class to be problem-specific classes. |
| 2021-03-21 17:56:02 | <dolio> | carter: Frank has a story. |
| 2021-03-21 17:56:32 | <carter> | frank the code or one of the papers on frank? is that the one where you write the handler sortha? |
| 2021-03-21 17:56:41 | <carter> | and install that in the dynamics/lexical scope? |
| 2021-03-21 17:57:03 | <dolio> | Not sure about the code, but there's a revised draft of the paper that talks about 'adaptors'. |
| 2021-03-21 17:57:09 | <edmundnoble> | Even that's arguably an XY problem |
| 2021-03-21 17:57:38 | <edmundnoble> | You don't get a good design for your program by just making all of the record fields into abstractions |
| 2021-03-21 17:57:51 | <carter> | yeah |
| 2021-03-21 17:57:53 | <dolio> | It basically allows you to do manual structural munging of the effect context. |
| 2021-03-21 17:58:03 | <carter> | which isn't something most people actually should do |
| 2021-03-21 17:58:14 | <carter> | what fancy things does that enable ? i forget |
| 2021-03-21 17:58:15 | <monochrom> | Yeah, probably ReadTime and HasTitle should be merged into one single MyProblemSpecificClass class. |
| 2021-03-21 17:58:32 | <monochrom> | and it just has to have a "gettime" method and a "gettile" method. |
| 2021-03-21 17:59:45 | <rybern> | chisui re: creating a product type - I could do that but it doesn't compose, I can't then partially execute one of the readers |
| 2021-03-21 17:59:56 | <dolio> | carter: It's essential for being abstract with respect to certain effects, at least. Like, you need to be able to say, 'handle the Foo effect in my code, but not the Foo effect in higher-order stuff passed into me,' because otherwise your types become littered with all the effect-based implementation details of your code. |
| 2021-03-21 18:00:24 | <dolio> | Because it will 'accidentally' handle the higher-order stuff that is supposed to be opaque to you. |
| 2021-03-21 18:01:15 | <dolio> | Koka has a similar thing. There's an example of how you can use it for, like, de Bruijn like multiple state variables, but that doesn't seem very compelling. |
| 2021-03-21 18:01:31 | <rybern> | carter re: one concrete stack -- this doesn't allow the same modularity IMO, e.g. you can't reuse functions between applications that have overlapping capabilities, and also I often change the stack throughout the application |
| 2021-03-21 18:01:33 | <dolio> | Because de Bruijn is bad for people to actually write. |
| 2021-03-21 18:01:41 | <carter> | yes you can |
| 2021-03-21 18:01:55 | <Franciman> | Haskell is a programming language for the past |
| 2021-03-21 18:01:56 | <carter> | rybern: you just make sure theres a type class for the reuse |
| 2021-03-21 18:02:11 | <Franciman> | thank you haskell for having become the past, it means you had a great influence on everybody |
| 2021-03-21 18:02:13 | <Franciman> | :') |
| 2021-03-21 18:02:44 | <rybern> | monochrom if I could avoid extra boilerplate for implementing ReadTime and HasTitle that would be great, but avoiding that an advantage of e.g. Ether |
| 2021-03-21 18:02:48 | × | alx741 quits (~alx741@181.196.69.79) (Ping timeout: 256 seconds) |
| 2021-03-21 18:03:01 | <maralorn> | ski: It’s nice how you said exactly what I meant by phrasing it like I had said the opposite. ^^ |
| 2021-03-21 18:03:13 | <monochrom> | You can newtype-wrap ReaderT Int for your instance of ReadTime. |
| 2021-03-21 18:03:51 | <rybern> | carter so is the idea to make a big stack, make a new typeclass for each capability i want, write instances for each capability for each stack? |
| 2021-03-21 18:03:55 | <edmundnoble> | Record structure is just not in itself a good design, neither is a rephrased version in terms of "effect structure". This is why encapsulation was such a big deal; turns out, exposing all of the details of your data structure is usually extremely brittle |
| 2021-03-21 18:04:07 | <carter> | rybern: one type class for your stack |
| 2021-03-21 18:04:14 | <carter> | unless you actually have a good reason to split it |
| 2021-03-21 18:04:28 | <edmundnoble> | Right, YAGNI |
| 2021-03-21 18:04:30 | <rybern> | monochrom I think that's what I didn't understand from capabilities library. How does that work when I have a big stack of ReaderTs? |
| 2021-03-21 18:04:30 | <carter> | but by default work wqith a new type wrappe ron your stack |
| 2021-03-21 18:04:45 | <carter> | agreed with edmundnoble |
| 2021-03-21 18:04:50 | <carter> | hes explaining it pretty nicely |
| 2021-03-21 18:05:13 | × | Hexagenic quits (~mattias@81-224-107-147-no71.tbcn.telia.com) (Ping timeout: 260 seconds) |
| 2021-03-21 18:06:00 | <carter> | any time you do a type synonym instead of a new type, stop and first try making it nice with a new type |
| 2021-03-21 18:06:13 | <carter> | is rule of thumb -11 |
| 2021-03-21 18:06:39 | → | vicfred joins (~vicfred@unaffiliated/vicfred) |
| 2021-03-21 18:06:53 | <rybern> | so say I have function x that uses capability (X m) and a function y that uses capability (Y m), and I want to share those between stacks that share those capabilities |
| 2021-03-21 18:07:08 | <rybern> | how does that work when I have one type class for my stack |
| 2021-03-21 18:07:29 | → | Shiranai joins (beed0df5@gateway/web/cgi-irc/kiwiirc.com/ip.190.237.13.245) |
| 2021-03-21 18:08:29 | <edmundnoble> | There is a tension here, you can't have totally fine-grained dependencies or you have brittleness |
| 2021-03-21 18:08:30 | → | tenniscp25 joins (~tenniscp2@134.196.209.118) |
| 2021-03-21 18:08:34 | <edmundnoble> | You have to choose how course-grained you want them to be |
| 2021-03-21 18:08:36 | <edmundnoble> | It's an art |
| 2021-03-21 18:08:48 | → | Hexagenic joins (~mattias@81-224-107-147-no71.tbcn.telia.com) |
| 2021-03-21 18:09:27 | <edmundnoble> | You don't get to just say "well I want to have all of everything always be pluggable everywhere", you have to define interfaces between components of your program |
| 2021-03-21 18:09:56 | <edmundnoble> | Type classes are tempting here because they sort of "automatically" propagate instances, but they can't solve this problem for you, just make some parts of it easier |
| 2021-03-21 18:10:07 | <carter> | yeah |
| 2021-03-21 18:10:17 | <carter> | you dont have abstraction till you name it :) |
| 2021-03-21 18:10:19 | <carter> | sortah |
| 2021-03-21 18:10:46 | → | heatsink joins (~heatsink@2600:1700:bef1:5e10:7956:c631:2eb4:a488) |
| 2021-03-21 18:11:07 | <Shiranai> | Hello I'm doing the fp-course and I have this function `readFile :: FilePath -> IO String`. I was trying to make the function `getFile :: FilePath -> IO (FilePath, String)`. My solution for that was `getFile f = lift2 (,) (readFile f) (pure f)`. The solution given was `getFile = lift2 (<$>) (,) readFile`. Thing is I have no idea what that code |
| 2021-03-21 18:11:07 | <Shiranai> | means. In particular, what does fmap here does? I.e. with respect with what functor is it? Same thing with lift2, with respect with what applicative is it? |
| 2021-03-21 18:11:17 | <rybern> | I'm happy to name things and define interfaces, that's not really what I'm asking |
| 2021-03-21 18:11:40 | <rybern> | In e.g. Ether, you give all of your capabilities tags, which does a nice job of naming things |
| 2021-03-21 18:12:02 | <rybern> | but you still get to use the derived behavior from mtl |
| 2021-03-21 18:12:12 | → | todda7 joins (~torstein@2a02:587:1b1c:3b00:c1d0:c187:5cec:e77f) |
| 2021-03-21 18:12:12 | <monochrom> | Sorry, what is "the fp-course" again? |
| 2021-03-21 18:12:46 | → | Vadrigar joins (~Vadrigar@ip5b417208.dynamic.kabel-deutschland.de) |
| 2021-03-21 18:13:17 | <monochrom> | And what is "lift2"? |
| 2021-03-21 18:13:43 | <edmundnoble> | Sure, what I'm saying is basically that there is a cost to having all of these named capabilities which you can sort of pull apart and operate on independently at will |
| 2021-03-21 18:13:47 | <bbhoss> | I'm counting the number of occurrences in a list, what's the best way to see if one of the occurrences is a majority of the list? I've got the count and was going to just check that `leaderCount > totalCount * 0.5` but I am getting a type error around the multiplication, because totalCount is an Int |
| 2021-03-21 18:14:10 | <edmundnoble> | And that cost is roughly speaking brittleness and low cohesion |
| 2021-03-21 18:14:15 | <monochrom> | And I think the intention is "lift2 (,) (pure f) (readFile f)" |
| 2021-03-21 18:14:33 | <edmundnoble> | This is why we put some effort into making pieces of code agree to work on particular monad transformer stacks |
| 2021-03-21 18:14:45 | <hpc> | bbhoss: you need to convert to a floating point number type |
| 2021-03-21 18:14:54 | <hpc> | or instead of multiplying by 0.5, you could multiply by 2 instead :P |
| 2021-03-21 18:14:59 | <Shiranai> | monochrom: https://github.com/system-f/fp-course The FileIO.hs , lift2 is lifta2 I think |
| 2021-03-21 18:15:04 | <edmundnoble> | Because if we didn't, maybe in the abstract it looks like we have code which "works totally independently", but we've only moved the complexity of using it together elsewhere |
| 2021-03-21 18:15:19 | <bbhoss> | is that what I really want? I guess I could convert and the get the ceil of the result? |
| 2021-03-21 18:15:34 | <Shiranai> | Monochrom: yeah I think the intention is what I wrote, but I have absolutely no idea how to translate it to that |
| 2021-03-21 18:15:38 | × | heatsink quits (~heatsink@2600:1700:bef1:5e10:7956:c631:2eb4:a488) (Ping timeout: 264 seconds) |
| 2021-03-21 18:15:40 | <bbhoss> | it's a voting system so accuracy is kinda important |
All times are in UTC.