Logs: liberachat/#haskell
| 2021-07-19 09:08:26 | <dminuoso> | So 1/0 is actually a well defined value, perhaps unintuitively. |
| 2021-07-19 09:09:18 | <dminuoso> | But, what you probably meant is: |
| 2021-07-19 09:09:22 | <dminuoso> | % 1 `div` 0 |
| 2021-07-19 09:09:22 | <yahb> | dminuoso: *** Exception: divide by zero |
| 2021-07-19 09:09:31 | <dminuoso> | % :t div |
| 2021-07-19 09:09:31 | <yahb> | dminuoso: Integral a => a -> a -> a |
| 2021-07-19 09:09:46 | × | Patternmaster quits (~georg@li1192-118.members.linode.com) (Ping timeout: 252 seconds) |
| 2021-07-19 09:09:58 | → | Patternmaster joins (~georg@li1192-118.members.linode.com) |
| 2021-07-19 09:10:02 | × | pavonia quits (~user@user/siracusa) (Quit: Bye!) |
| 2021-07-19 09:10:04 | <albet70> | yes, div 0 |
| 2021-07-19 09:10:07 | <dminuoso> | albet70: ^- so yeah, this is a partial computation. We could have also made it non-partial and given it the type `div :: Integral a => a -> a -> Maybe a`, which produces Nothing for that case. |
| 2021-07-19 09:10:30 | × | jolly quits (~jolly@208.180.97.158) (Ping timeout: 252 seconds) |
| 2021-07-19 09:12:02 | <dminuoso> | albet70: In general, it's better to encode a failure as `Maybe` or `Either s` rather than producing an error (like div does) |
| 2021-07-19 09:12:34 | <dminuoso> | albet70: The reason is, you cant catch an `error` sensibly (its impossible in pure code, and you have imprecise error semantics if you try to do this from IO). error is really a sad part in Haskell. |
| 2021-07-19 09:12:55 | <dminuoso> | But you can catch a Nothing just fine (you just pattern match with case-of) |
| 2021-07-19 09:13:02 | <dminuoso> | Dont even need IO for that. |
| 2021-07-19 09:14:21 | → | lavaman joins (~lavaman@98.38.249.169) |
| 2021-07-19 09:15:25 | <albet70> | but haskell does try catch to capture runtime errors like IO error |
| 2021-07-19 09:15:48 | <albet70> | and IO socket error, how to use Either to detect? |
| 2021-07-19 09:16:01 | <dminuoso> | haskell does not try and catch runtime errors at all |
| 2021-07-19 09:16:08 | <dminuoso> | They blow up your entire program |
| 2021-07-19 09:17:30 | <dminuoso> | You have to explicitly catch them in IO |
| 2021-07-19 09:17:44 | <dminuoso> | And it's subtly difficult to do this because of lazy evaluation |
| 2021-07-19 09:17:47 | <dminuoso> | Consider |
| 2021-07-19 09:17:49 | <dminuoso> | % :t evaluate |
| 2021-07-19 09:17:49 | <yahb> | dminuoso: a -> IO a |
| 2021-07-19 09:18:39 | <dminuoso> | This one only evaluates up until WHNF. You could still have errors lingering in not-yet-evaluated parts. There's tricks to get around this, but you need to be aware of this |
| 2021-07-19 09:18:57 | × | lavaman quits (~lavaman@98.38.249.169) (Ping timeout: 250 seconds) |
| 2021-07-19 09:19:34 | <dminuoso> | It's why uses of `error` are highly discouraged, since it's completely unclear which library functions could possibly trigger an `error`. The most common one that regularly causes headaches for me is\ |
| 2021-07-19 09:19:36 | <dminuoso> | % :t read |
| 2021-07-19 09:19:36 | <yahb> | dminuoso: Read a => String -> a |
| 2021-07-19 09:19:56 | <dminuoso> | If you think about it, it should be dead obvious that this is *very* partial (by very I mean almost all strings produce an invalid result, only very few strings produce a parsable value) |
| 2021-07-19 09:20:24 | <dminuoso> | But this type of error quickly bubbles up and cant be reasonably caught anymore |
| 2021-07-19 09:20:55 | <dminuoso> | A way better function instead is: |
| 2021-07-19 09:20:57 | <dminuoso> | % :t readMaybe |
| 2021-07-19 09:20:57 | <yahb> | dminuoso: ; <interactive>:1:1: error: Variable not in scope: readMaybe |
| 2021-07-19 09:21:07 | <dminuoso> | % import Data.Text (readMaybe) |
| 2021-07-19 09:21:07 | <yahb> | dminuoso: ; <interactive>:1:19: error: Module `Data.Text' does not export `readMaybe' |
| 2021-07-19 09:21:17 | <dminuoso> | % import Text.Read (readMaybe) |
| 2021-07-19 09:21:18 | <yahb> | dminuoso: |
| 2021-07-19 09:21:19 | <dminuoso> | % :t readMaybe |
| 2021-07-19 09:21:19 | <yahb> | dminuoso: Read a => String -> Maybe a |
| 2021-07-19 09:27:02 | → | rahguzar joins (~rahguzar@dynamic-adsl-94-34-39-251.clienti.tiscali.it) |
| 2021-07-19 09:27:55 | → | azeem joins (~azeem@dynamic-adsl-94-34-39-251.clienti.tiscali.it) |
| 2021-07-19 09:28:04 | × | rahguzar quits (~rahguzar@dynamic-adsl-94-34-39-251.clienti.tiscali.it) (Client Quit) |
| 2021-07-19 09:35:05 | × | dibblego quits (~dibblego@haskell/developer/dibblego) (Excess Flood) |
| 2021-07-19 09:35:22 | → | dibblego joins (~dibblego@122-199-1-30.ip4.superloop.com) |
| 2021-07-19 09:35:22 | × | dibblego quits (~dibblego@122-199-1-30.ip4.superloop.com) (Changing host) |
| 2021-07-19 09:35:22 | → | dibblego joins (~dibblego@haskell/developer/dibblego) |
| 2021-07-19 09:39:05 | × | tom__ quits (~tom@2a00:23c8:9700:8001:a918:fa2c:4713:fcbd) (Remote host closed the connection) |
| 2021-07-19 09:41:07 | × | MQ-17J quits (~MQ-17J@d14-69-206-129.try.wideopenwest.com) (Ping timeout: 246 seconds) |
| 2021-07-19 09:45:03 | → | dunj3 joins (~dunj3@2001:16b8:3046:8200:9324:28de:5bca:d5dc) |
| 2021-07-19 09:45:16 | → | MQ-17J joins (~MQ-17J@d14-69-206-129.try.wideopenwest.com) |
| 2021-07-19 09:47:09 | × | yauhsien quits (~yauhsien@61-231-35-149.dynamic-ip.hinet.net) (Remote host closed the connection) |
| 2021-07-19 09:47:45 | × | peterhil quits (~peterhil@mobile-access-b04801-219.dhcp.inet.fi) (Ping timeout: 268 seconds) |
| 2021-07-19 09:48:35 | → | lavaman joins (~lavaman@98.38.249.169) |
| 2021-07-19 09:49:15 | → | jumper149 joins (~jumper149@80.240.31.34) |
| 2021-07-19 09:53:01 | × | lavaman quits (~lavaman@98.38.249.169) (Ping timeout: 246 seconds) |
| 2021-07-19 10:06:07 | <guest719> | dminuoso about traverse "<dminuoso> Say you have a tree, and you want to process each node - but in a way that if you generate an error at any, that the entire computation is considered failed." could we use foldr >=> pure here? |
| 2021-07-19 10:06:36 | <guest719> | a bunch of function inside a list, then foldr |
| 2021-07-19 10:07:08 | <guest719> | apply on this tree, if one node failed, then return immediatly |
| 2021-07-19 10:14:45 | <jumper149> | Is it wrong to say "MonadPlus is obsolete"? Just like `return` is obsolete because of `pure`? |
| 2021-07-19 10:16:00 | × | eggplantade quits (~Eggplanta@108-201-191-115.lightspeed.sntcca.sbcglobal.net) (Remote host closed the connection) |
| 2021-07-19 10:16:04 | × | hexfive quits (~eric@50.35.83.177) (Quit: WeeChat 3.0) |
| 2021-07-19 10:16:16 | × | burnsidesLlama quits (~burnsides@dhcp168-011.wadham.ox.ac.uk) (Remote host closed the connection) |
| 2021-07-19 10:19:15 | × | xsperry quits (~as@user/xsperry) (Remote host closed the connection) |
| 2021-07-19 10:19:25 | → | Ariakenom joins (~Ariakenom@c83-255-154-140.bredband.tele2.se) |
| 2021-07-19 10:20:44 | → | xsperry joins (~as@user/xsperry) |
| 2021-07-19 10:21:23 | → | peterhil joins (~peterhil@mobile-access-b04801-219.dhcp.inet.fi) |
| 2021-07-19 10:22:22 | × | jmorris quits (uid433911@id-433911.stonehaven.irccloud.com) (Quit: Connection closed for inactivity) |
| 2021-07-19 10:23:45 | → | moondog joins (~root@185.234.208.208.r.toneticgroup.pl) |
| 2021-07-19 10:25:06 | <moondog> | hi, quick question, suppose I'd like to parse Haskell files to find particular method calls and it's argument types, where should I start? Is there any tooling for that to avoid writing everything from scratch? |
| 2021-07-19 10:25:24 | <dminuoso> | guest719: Firstly, `f >=> pure = f` |
| 2021-07-19 10:25:25 | → | Brianmancer joins (~Neuromanc@user/briandamag) |
| 2021-07-19 10:25:44 | <dminuoso> | guest719: And what you are thinking of already is traverse precisely. |
| 2021-07-19 10:25:47 | <dminuoso> | % :t traverse |
| 2021-07-19 10:25:47 | <yahb> | dminuoso: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b) |
| 2021-07-19 10:26:33 | <guest719> | dminuoso fmap can't do early exit because it's type, but >>= can do early exit |
| 2021-07-19 10:26:48 | <dminuoso> | guest719: Yes, and traverse uses >> internally |
| 2021-07-19 10:26:56 | <dminuoso> | (So it's a bit more general even) |
| 2021-07-19 10:26:56 | <guest719> | dminuoso I remeber there're different between fmap and >>= |
| 2021-07-19 10:27:10 | <dminuoso> | % :t (>>) |
| 2021-07-19 10:27:10 | <yahb> | dminuoso: Monad m => m a -> m b -> m b |
| 2021-07-19 10:27:11 | <guest719> | >>= can do if-else, and fmap can't do if-else |
| 2021-07-19 10:27:17 | <dminuoso> | Well, strictly speaking: |
| 2021-07-19 10:27:20 | <dminuoso> | % :t (*>) |
| 2021-07-19 10:27:20 | <yahb> | dminuoso: Applicative f => f a -> f b -> f b |
| 2021-07-19 10:27:54 | <dminuoso> | guest719: `traverse` can be thought to use (*>) internally, which is just an Applicative version of >> |
| 2021-07-19 10:28:04 | <dminuoso> | Roughly the idea is: |
| 2021-07-19 10:29:17 | → | merijn joins (~merijn@83-160-49-249.ip.xs4all.nl) |
| 2021-07-19 10:29:39 | <dminuoso> | We take this function (a -> f b) (say `String -> IO Int`)from above, and we `fmap` over the structure (say `[String]`). Then, each value is replaced with a computation of some type (say `IO Int`), so the whole structure then is `[IO Int]`. |
| 2021-07-19 10:29:55 | <dibblego> | you might be thinking of traverse_ |
| 2021-07-19 10:29:58 | <dminuoso> | Then we `sequence` this, which turns `[IO Int] -> IO [Int]` |
| 2021-07-19 10:32:32 | <dminuoso> | Imagine this to be: sequence (x:xs) = (:) <$> x <*> sequence xs; sequence [] = pure [] |
| 2021-07-19 10:32:58 | <dminuoso> | dibblego: Ah yeah. I guess that was wrong of me. |
| 2021-07-19 10:33:06 | <dminuoso> | While I was typing the definition, I realized my mistake. |
| 2021-07-19 10:33:44 | <dminuoso> | % mySequence (x:xs) = (:) <$> x <*> mySequence xs; mySequence [] = pure [] |
| 2021-07-19 10:33:44 | <yahb> | dminuoso: |
| 2021-07-19 10:33:46 | <dminuoso> | % :t mySequence |
| 2021-07-19 10:33:46 | <yahb> | dminuoso: Applicative f => [f a] -> f [a] |
All times are in UTC.