Logs: liberachat/#haskell
| 2021-08-30 08:03:58 | <maerwald[m]> | Like a web page going blank in production, because you deleted a bracket at a wrong place and the code still compiled |
| 2021-08-30 08:04:38 | <kuribas> | maerwald[m]: we've had a client complaining because our code broke due to a type error. |
| 2021-08-30 08:04:48 | <kuribas> | email reporting I mean... |
| 2021-08-30 08:04:59 | <maerwald[m]> | Yes, the only advantage of clojure, interactive development |
| 2021-08-30 08:05:31 | <kuribas> | interactive development is much worse in haskell, but I still prefer it, because I am not "forced" to use the repl. |
| 2021-08-30 08:05:32 | → | hendursa1 joins (~weechat@user/hendursaga) |
| 2021-08-30 08:05:42 | <kuribas> | I just use it when *I* want to. |
| 2021-08-30 08:06:16 | × | mikoto-chan quits (~mikoto-ch@ip-83-134-2-136.dsl.scarlet.be) (Quit: mikoto-chan) |
| 2021-08-30 08:06:39 | <maerwald[m]> | I stopped interactive development in haskell and it made me better at coding. Thinking for more than 5 minutes about code without compiling it has an interesting effect |
| 2021-08-30 08:07:28 | <maerwald[m]> | And it's a pleasure when things compile after you've been editing for 30 minutes |
| 2021-08-30 08:07:36 | <kuribas> | maerwald[m]: I test my code *after* writing it. |
| 2021-08-30 08:08:36 | × | hendursaga quits (~weechat@user/hendursaga) (Ping timeout: 276 seconds) |
| 2021-08-30 08:12:49 | × | rbocquet quits (~weechat@2001:bc8:47a8:44e::1) (Quit: WeeChat 2.8) |
| 2021-08-30 08:16:10 | → | rbocquet joins (~weechat@2001:bc8:47a8:44e::1) |
| 2021-08-30 08:17:15 | → | arjun joins (~Srain@user/arjun) |
| 2021-08-30 08:17:53 | <arjun> | Hi, i'm inside a function with some constraints (MonadIO m, MonadCatch m .... etc) |
| 2021-08-30 08:18:08 | <arjun> | now one of the arguments is a Maybe FilePath |
| 2021-08-30 08:18:39 | <arjun> | and i can't seem to do ` dir <- givenPath ` inside the `do` |
| 2021-08-30 08:18:40 | × | notzmv quits (~zmv@user/notzmv) (Ping timeout: 240 seconds) |
| 2021-08-30 08:18:53 | <arjun> | " Couldn't match type ‘m’ with ‘Maybe’ " |
| 2021-08-30 08:19:18 | <arjun> | while, i could do `let dir = fromJust givenPath` just fine |
| 2021-08-30 08:19:26 | <merijn> | Maybe is not an instance of MonadIO, so you can't do that, no |
| 2021-08-30 08:20:19 | × | azeem quits (~azeem@176.200.56.216) (Ping timeout: 250 seconds) |
| 2021-08-30 08:20:21 | <arjun> | bump. |
| 2021-08-30 08:21:08 | <arjun> | what's the prefered way to do this kindda thing, just for my curiosity's sake |
| 2021-08-30 08:21:41 | <kuribas> | arjun: don't use fromJust, use fromMaybe instead. |
| 2021-08-30 08:21:45 | <kuribas> | :t fromJust |
| 2021-08-30 08:21:46 | <lambdabot> | Maybe a -> a |
| 2021-08-30 08:21:50 | <kuribas> | :t fromMaybe |
| 2021-08-30 08:21:50 | <merijn> | "preferred way to do this" <- you haven't really specified what "this" is |
| 2021-08-30 08:21:51 | <lambdabot> | a -> Maybe a -> a |
| 2021-08-30 08:22:24 | <merijn> | arjun: You have said "I have a Maybe FilePath", but not really anything about how you wanna use it or what you expect to happen |
| 2021-08-30 08:22:27 | <kuribas> | arjun: fromJust will crash when you pass a Nothing, with a very unhelpful message. |
| 2021-08-30 08:22:29 | → | azeem joins (~azeem@62.18.127.19) |
| 2021-08-30 08:22:33 | <arjun> | kuribas: yea, just repl'd it. fromJust is unsafe if i get Nothing |
| 2021-08-30 08:23:08 | <kuribas> | arjun: as merijn said, you have to figure out what to do when it's `Nothing`. |
| 2021-08-30 08:23:45 | <arjun> | merijn: get a value from Just if it's Just (for eg get 5 from Just 5) and Nothing if it's Nothing from a polymorphic function with constraints ? does that make sense? |
| 2021-08-30 08:24:13 | <arjun> | merijn: i understand Maybe not having a MonadIO instance |
| 2021-08-30 08:24:25 | <merijn> | That doesn't really make sense no |
| 2021-08-30 08:24:38 | <merijn> | What does "getting Nothing if it's Nothing" mean |
| 2021-08-30 08:24:44 | <arjun> | kuribas: i see. i was hoping "<-" would take care of it for me : P |
| 2021-08-30 08:24:50 | <merijn> | <- is not magic |
| 2021-08-30 08:24:57 | <merijn> | <- is just sugar for >>= |
| 2021-08-30 08:25:00 | <merijn> | :t (>>=) |
| 2021-08-30 08:25:02 | <lambdabot> | Monad m => m a -> (a -> m b) -> m b |
| 2021-08-30 08:25:02 | → | rtpg joins (sid443069@charlton.irccloud.com) |
| 2021-08-30 08:25:08 | <kuribas> | arjun: you mean, <- would pry into your mind, and do the right thing? |
| 2021-08-30 08:25:10 | <merijn> | That means all sides have to be the same 'm' |
| 2021-08-30 08:25:40 | <kuribas> | arjun: or better, infer the business logic that needs to apply in this case? |
| 2021-08-30 08:25:46 | → | __monty__ joins (~toonn@user/toonn) |
| 2021-08-30 08:25:48 | <arjun> | kuribas: it should also write the docs, white it's at it : P |
| 2021-08-30 08:25:55 | <merijn> | arjun: Specifically, if you *did* use <- with Maybe, then they entire do block would be a "Maybe" type |
| 2021-08-30 08:25:58 | <arjun> | while* |
| 2021-08-30 08:26:03 | <kuribas> | arjun: cool, let me know when you find this :) |
| 2021-08-30 08:26:25 | <merijn> | arjun: And your function wouldn't be "foo :: MonadIO m => Maybe FilePath -> m ()" it'd just be "foo :: Maybe FilePath -> Maybe ()" or whatever |
| 2021-08-30 08:26:39 | <arjun> | merijn: yes, that's what the error is saying i suppose (hard to read for untrained eyes) |
| 2021-08-30 08:27:00 | → | burnsidesLlama joins (~burnsides@dhcp168-015.wadham.ox.ac.uk) |
| 2021-08-30 08:27:20 | <arjun> | my function is expected to return m Bool, but it returns a fixed type Maybe .. |
| 2021-08-30 08:27:38 | <arjun> | i see. |
| 2021-08-30 08:27:46 | <arjun> | thanks ! merijn |
| 2021-08-30 08:28:08 | <rtpg> | Has there ever been any discussion of having Haskell adopt anonymous sum types? That is to say, instead of using Either Int Bool, being able to write out Int | Bool and pattern match directly off of that? Essentially making sum types first-class in the same way products are |
| 2021-08-30 08:28:41 | <[exa]> | (product types are first class?) |
| 2021-08-30 08:28:47 | <opqdonut> | sums are first-class in exactly the same way as products |
| 2021-08-30 08:28:55 | <opqdonut> | both have their type constructor: (,) and Either |
| 2021-08-30 08:29:38 | <opqdonut> | (and you have the ADT syntax which allows you to define a custom collection of sums and products and give it a name) |
| 2021-08-30 08:29:39 | <arjun> | why do i always get the image of people evacuating the Titanic when it's drowning when people say "first class" |
| 2021-08-30 08:30:13 | <rtpg> | I think it's pretty easy to argue that tuples are ... more.... first-class (like I don't have to give names, I can do N-products instead of stacking with Either). But I get your point from a mechanical level |
| 2021-08-30 08:30:45 | <kuribas> | rtpg: tuples have type constructors as well. |
| 2021-08-30 08:31:24 | <rtpg> | At least for me, Typescript allows for using anonymous unions, and then is able to very easily deduce what your thing is without having you need to name some helper type like StringOrPropertyAccessorOrInteger |
| 2021-08-30 08:32:51 | <kuribas> | rtpg: you should never name things like that :) |
| 2021-08-30 08:33:25 | <[exa]> | rtpg: you can't reliably infer an anonymous union without abusing a closed-world assumption |
| 2021-08-30 08:34:51 | <[exa]> | rtpg: what about just making a tiny typeclass for that? |
| 2021-08-30 08:34:58 | <rtpg> | ah that's a good point, suddenly it's like "is this supposed to return A | B or is it meant to return A and B is a mistake" |
| 2021-08-30 08:35:34 | <[exa]> | stuff like "f :: MyFunctionWorksWith a => a -> a" is pretty common I'd say |
| 2021-08-30 08:35:38 | <rtpg> | I mean y'all never just have a bucket of things that exist in some inner function that don't have much semantic value beyond being the return type of a handful of objects? |
| 2021-08-30 08:36:27 | <kuribas> | rtpg: in lisps often they make one function do a lot of things. The haskell way is more to have different "combinators", to provide different features. |
| 2021-08-30 08:36:35 | <kuribas> | rtpg: it works better with static typing |
| 2021-08-30 08:36:53 | <rtpg> | though yeah I guess I don't mind making the function itself have to be explicit, it's more around callsites, I would love to pattern match directly on A | B without having to unwrap an Either first. But I guess with Rust I end up taking a trait anyways |
| 2021-08-30 08:36:56 | <merijn> | rtpg: Datatypes are cheap to define in Haskell |
| 2021-08-30 08:36:57 | <[exa]> | rtpg: or, say. `mySemanticOf :: HasMySemantics a => a -> Bool`, and use it to downcast the many possibilities to something predictable |
| 2021-08-30 08:37:09 | <merijn> | rtpg: So, might as well define a datatype |
| 2021-08-30 08:37:34 | <kuribas> | rtpg: err, how would you pattern match on A | B, if you don't have a constructor? |
| 2021-08-30 08:38:00 | <merijn> | rtpg: In fact, as my projects scale up, the more I love previous me for defining lots and lots of custom datatypes |
| 2021-08-30 08:39:33 | × | eggplantade quits (~Eggplanta@2600:1700:bef1:5e10:10be:968:241f:1aa6) (Remote host closed the connection) |
| 2021-08-30 08:39:47 | × | hyiltiz quits (~quassel@31.220.5.250) (Ping timeout: 240 seconds) |
| 2021-08-30 08:40:05 | <rtpg> | let's say you have Foo = Bar Int | Baz String, and like Mouse Int, then Foo | Mouse you could pattern match like "f:: (Foo | Mouse) -> Int" and just directly "f (Bar i) = i; f (Baz s) = length s, f (Mouse m) = m" |
| 2021-08-30 08:41:11 | <kuribas> | merijn: the same for me. And my code becomes more readable. |
| 2021-08-30 08:41:31 | <rtpg> | this is very much a "thought about for a little bit" thing, where how the compiler turns this into executable code is probably tricky. TS doesn't have that problem since it doesn't have to actually evaluate the code of course |
| 2021-08-30 08:41:39 | → | hyiltiz joins (~quassel@31.220.5.250) |
| 2021-08-30 08:42:26 | <merijn> | rtpg: How is writing (Foo | Mouse) in a function better than taking 1 line to define an ADT that implements that? :p |
| 2021-08-30 08:43:03 | <rtpg> | FooOrMouse = Either Foo Mouse , then I'm writing Left (Bar i) and Left (Baz s) blah blah blah.... it's all line noise to me in that case |
| 2021-08-30 08:43:29 | <rtpg> | like sometimes things don't have any conceptual meaning outside of one specific spot! Surely you have had situations where a thing just doesn't have a good name available for it right? |
| 2021-08-30 08:43:30 | <kuribas> | important semantic information /= line noise |
| 2021-08-30 08:44:53 | <rtpg> | I don't believe that saying Either and then Left/Right in this case is adding extra semantic information in these kinds of cases (where you're really just wanting a sum type). This isn't a general judgement on all sum types, just wondering if this is a thing that has been discussed |
| 2021-08-30 08:45:13 | <merijn> | rtpg: I didn't say either, I said defining your own ADT |
| 2021-08-30 08:45:48 | × | shriekingnoise quits (~shrieking@186.137.144.80) (Quit: Quit) |
| 2021-08-30 08:46:36 | <rtpg> | You know that base lisp thing where if you want to define a variable with a let, you end up introducing indentation into your code that wouldn't exist in, say, Python/C? I feel the same way with introducing the intermediate ADT in my example (even if in the internals something would have to be done to get that to work) |
| 2021-08-30 08:47:59 | <kuribas> | rtpg: my take is that if you have lots of intermediate ADTs like that, your not thinking in a haskell way... |
| 2021-08-30 08:48:15 | <kuribas> | see my comment above |
| 2021-08-30 08:49:24 | <kuribas> | If I write my functions in haskell as I would write lisp, it may end up like that. |
All times are in UTC.