Home freenode/#haskell: Logs Calendar

Logs: freenode/#haskell

←Prev  Next→ 502,152 events total
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.