Logs: freenode/#haskell
| 2021-04-19 18:22:37 | <tomsmeding> | MrFantastik: play around with the idea, with only reading I estimate the chance very small that you'll get real understanding |
| 2021-04-19 18:22:45 | <Cale> | MrFantastik: So, my favourite example is parsers. It's possible in Haskell (and other typed functional programming languages) to define a type Parser t for things that try to consume some portion of a string, and if successful, will produce a result of type t |
| 2021-04-19 18:23:12 | <tomsmeding> | MrFantastik: and that holds for all "you", not only MrFantastik in particular :p |
| 2021-04-19 18:23:12 | → | fiedlr joins (~fiedlr@83.148.33.254) |
| 2021-04-19 18:23:49 | <tomsmeding> | (unless, that is, you understand what a monoid in the category of endofunctors is -- some do) |
| 2021-04-19 18:23:54 | <monochrom> | Yeah I leverage Maybe and [] playing dual roles of being data and being simple models of non-functions, when I teach functor, applicative, monad. |
| 2021-04-19 18:24:06 | <Cale> | MrFantastik: There are a fair number of parsing libraries in Haskell which basically set out by defining a type like that, and some basic parsers for consuming a single character, or trying to match a particular string, or things like that, and then ways of combining simple parsers together to make more complicated ones |
| 2021-04-19 18:24:24 | <safinaskar> | yushyin: thanks |
| 2021-04-19 18:24:29 | <monochrom> | non-function programs |
| 2021-04-19 18:24:34 | <MrFantastik> | Cale: that sounds interesting |
| 2021-04-19 18:25:00 | <Cale> | A very basic primitive type of parser is the one which consumes none of its input, but succeeds, and produces a given result. We'll have a function: |
| 2021-04-19 18:25:06 | <Cale> | return :: t -> Parser t |
| 2021-04-19 18:25:08 | <monochrom> | Oh generally it is true that you never understand something until you need to use it. |
| 2021-04-19 18:25:31 | <Cale> | which given a value, constructs that "do nothing, successfully" sort of parser |
| 2021-04-19 18:25:46 | <monochrom> | This is why I still don't sweat myself to learn lens or Day convolutions or... |
| 2021-04-19 18:26:33 | <Cale> | MrFantastik: Okay so far? |
| 2021-04-19 18:27:04 | <Cale> | return is one of the two functions that we need to define to make Parser into a monad. |
| 2021-04-19 18:27:50 | → | Deide joins (~Deide@217.155.19.23) |
| 2021-04-19 18:28:08 | <Cale> | The other, is pronounced "bind" and written (>>=) and its type might be a bit of a mouthful at first: |
| 2021-04-19 18:28:16 | <Cale> | (>>=) :: Parser a -> (a -> Parser b) -> Parser b |
| 2021-04-19 18:28:45 | <Cale> | This function takes a parser x, and some function f that's capable of consuming the results of the first parser, and producing a second parser |
| 2021-04-19 18:28:54 | <tomsmeding> | basenode: a general recipe to do your thing without laziness is: construct a map (id => parent id); construct a map (id => child id's); perform a topological sort on that last map to get a list of ids; iterate over that list in reverse, building a map (id => Node) where 'data Node = Node id [Node]'; pick the roots from that map |
| 2021-04-19 18:29:24 | <tomsmeding> | though that does still require sharing, but every purely functional language should have that |
| 2021-04-19 18:29:31 | × | dyeplexer quits (~lol@unaffiliated/terpin) (Remote host closed the connection) |
| 2021-04-19 18:29:33 | <Cale> | and it stitches them together to make a parser which, when you run it on some string, will try to consume the initial portion of the input with x, and if it succeeds with some result v, will parse the remainder of the input with f v |
| 2021-04-19 18:30:00 | <MrFantastik> | and if Parser a fails? |
| 2021-04-19 18:30:09 | <Cale> | Then the combined parser fails |
| 2021-04-19 18:30:20 | → | frozenErebus joins (~frozenEre@37.231.244.249) |
| 2021-04-19 18:30:21 | <MrFantastik> | what would it return then? |
| 2021-04-19 18:30:34 | <MrFantastik> | or would there be some sort of exception raised? |
| 2021-04-19 18:30:36 | → | ddellacosta joins (~ddellacos@ool-44c73afa.dyn.optonline.net) |
| 2021-04-19 18:30:41 | ← | safinaskar parts (~user@109.252.90.136) () |
| 2021-04-19 18:31:16 | <ski> | tomsmeding : i mentioned topologically sorting, then building bottom-up, in ##programming, to basenode, before |
| 2021-04-19 18:31:27 | <Cale> | It's similar to an exception, even if it's not *technically* one -- generally it's built into the definition of Parser t that it's possible for a parser to produce zero results, or fail with some error |
| 2021-04-19 18:32:04 | <Cale> | To make that more concrete, one possible implementation for a type like this (even if it's a little inefficient, it's simple) looks like: |
| 2021-04-19 18:32:21 | <basenode> | tomsmeding: yeah ski also mentioned that, i just have no experience with topological sort :P |
| 2021-04-19 18:32:30 | <basenode> | but i'll do some research, thanks for the help guys |
| 2021-04-19 18:32:34 | <tomsmeding> | you can look up algorithms for that :p |
| 2021-04-19 18:32:42 | <Cale> | data Parser t = MkParser (String -> [(t, String)]) |
| 2021-04-19 18:32:59 | <tomsmeding> | I think you cannot get around a topsort; isn't this problem basically _equivalent_ to a topsort |
| 2021-04-19 18:33:00 | <Cale> | That is, a parser for things, is a function from strings to lists of pairs of things and strings :D |
| 2021-04-19 18:33:16 | → | star_cloud joins (~star_clou@ec2-34-220-44-120.us-west-2.compute.amazonaws.com) |
| 2021-04-19 18:33:20 | <Cale> | The idea being that the parser may fail, and produce an empty list in that case |
| 2021-04-19 18:33:34 | <Cale> | Or it may succeed in a unique way, returning a list of length 1 |
| 2021-04-19 18:33:56 | <Cale> | Or it might succeed in multiple ways (if the parse is ambiguous), returning a longer list |
| 2021-04-19 18:34:09 | <Cale> | and in each case, the pairs in the list are the parsed result, and the remaining portion of the input |
| 2021-04-19 18:34:10 | <tomsmeding> | basenode: if you manage to implement your problem without a topsort, then you can define a topsort function in terms of your solution |
| 2021-04-19 18:34:10 | <ski> | the cyclic construction of the table of trees effectively (implicitely) does toposort, yea |
| 2021-04-19 18:34:17 | <tomsmeding> | so if you want it or not, you're going to do a topsort :p |
| 2021-04-19 18:34:52 | <basenode> | topsort it is then! |
| 2021-04-19 18:34:54 | ski | idly recalls first hearing of toposort, in BASIC (with line numbers) |
| 2021-04-19 18:35:06 | × | frozenErebus quits (~frozenEre@37.231.244.249) (Ping timeout: 240 seconds) |
| 2021-04-19 18:35:39 | <wroathe> | MrFantastik: Cale: You asked about exceptions. It might be illustrative to look at the definition for the "Either" monad to illustrate one way this is handled. |
| 2021-04-19 18:35:42 | <wroathe> | MrFantastik: https://gitlab.haskell.org/ghc/ghc/-/blob/master/libraries/base/Data/Either.hs#L157-159 |
| 2021-04-19 18:36:20 | <wroathe> | MrFantastik: That "interface" I was referring to was the ability to define "return" (aka "pure", above). and >>= |
| 2021-04-19 18:36:57 | <Cale> | Oh, right, it's worth pointing out that we can define a monad that simulates exceptions :) |
| 2021-04-19 18:37:06 | <wroathe> | MrFantastik: An Either value is either a Left or a Right. It's a tagged union, if you're familiar with those in other languages. If the value is a left, it's an error state, and if it's a right, it's a value state |
| 2021-04-19 18:37:33 | <wroathe> | MrFantastik: So if the Either value on the left hand side of >>= is a Left, we just "skip" the computation that would've otherwise been performed |
| 2021-04-19 18:37:50 | <wroathe> | MrFantastik: And if it's a Right, we perform the computation like normal |
| 2021-04-19 18:37:53 | × | chele quits (~chele@5.53.222.202) (Remote host closed the connection) |
| 2021-04-19 18:37:58 | <ski> | wroathe : yea .. i was circumambulating around the concepts, trying to set the context a bit more clearly, dispelling some misconceptions, and give some hopefully useful clues to get a better handle on them (it wasn't really intended as a tutorial) |
| 2021-04-19 18:38:28 | × | lambdaman quits (~lambdaman@s66-183-152-156.bc.hsia.telus.net) (Remote host closed the connection) |
| 2021-04-19 18:40:42 | <wroathe> | ski: In what context? Are you saying that none of what we discussed was a good way to help a beginner understand monads? |
| 2021-04-19 18:40:56 | <wroathe> | ski: I thought we landed on some good models for explanation there |
| 2021-04-19 18:41:07 | → | nut joins (~user@roc37-h01-176-170-197-243.dsl.sta.abo.bbox.fr) |
| 2021-04-19 18:41:20 | × | nut quits (~user@roc37-h01-176-170-197-243.dsl.sta.abo.bbox.fr) (Remote host closed the connection) |
| 2021-04-19 18:41:56 | <MrFantastik> | so as i understand it |
| 2021-04-19 18:42:07 | → | nut joins (~user@roc37-h01-176-170-197-243.dsl.sta.abo.bbox.fr) |
| 2021-04-19 18:42:29 | <wroathe> | MrFantastik: So with that Either monad, if you were to do something like (Left "oh noes, this is an error" >>= addThree >>= timesTwo) the result of this expression would be Left "oh noes, this is an error" (ignoring the second and third terms). |
| 2021-04-19 18:42:35 | <MrFantastik> | a monad can help assign a type to a value that's type is unkown, but later will be known after the result of some function? |
| 2021-04-19 18:42:40 | <wroathe> | MrFantastik: But if you did Left "oh noes, this is an error" >>= addThree >>= timesTwo |
| 2021-04-19 18:42:43 | <wroathe> | Ignore that |
| 2021-04-19 18:42:48 | <wroathe> | mispaste |
| 2021-04-19 18:43:07 | <wroathe> | But if you did Right 3 >>= addThree >>= timesTwo the value would be Right 12 |
| 2021-04-19 18:43:47 | <Cale> | MrFantastik: Well, yeah, quite often, the type that our monad is parameterised by will be the type of the eventual result of some computation. |
| 2021-04-19 18:44:06 | <Cale> | (In fact, it's always possible to think of it that way) |
| 2021-04-19 18:44:47 | <ski> | wroathe : i think (hope) that the discussion would be of some use to (a) people trying to talk about and explain monads to others; (b) people trying to get a better grip on what monad's for. (those are overlapping). however, i wasn't really trying to aim at explaining monads (people seem to agree that you (or most people, anyway) most likely really need to see more specific examples of monads, and how |
| 2021-04-19 18:44:54 | <ski> | they're used) |
| 2021-04-19 18:46:21 | <wroathe> | ski: Well, I suppose I disagree and think that the discussion was helpful for explaining monads. The interface part is a very tangible thing that people who have programmed in other languages can easily grasp. |
| 2021-04-19 18:46:35 | <ski> | i was more aiming at attempting to clarify some surrounding concepts, dispel some confusion, that i don't that often see ventilated, that could serve to help someone make more sense of it, in adjunction with additional material |
| 2021-04-19 18:47:26 | <wroathe> | ski: And then if you tackle the problem of sequencing in a lazy functional language you start getting close to an explanation for 1. what they are and 2. why they're used |
| 2021-04-19 18:47:37 | <ski> | wroathe : and yea, it was intended to be helpful. but if i were aiming to explain monads (in a more self-contained way, not relying on external sources), i'd have to walk through a lot more examples that i managed to do, there |
| 2021-04-19 18:48:06 | <wroathe> | ski: Well, that latter point is why we have books |
| 2021-04-19 18:48:20 | <wroathe> | ski: There's plenty of monad tutorials out there that tackle one monad definition at a time |
| 2021-04-19 18:48:26 | <ski> | yea. and some on-line resources |
| 2021-04-19 18:48:45 | <ski> | (unfortunately, most monad tutorials out there seem to range from bad to worse) |
| 2021-04-19 18:48:46 | × | haritz quits (~hrtz@unaffiliated/haritz) (Quit: ZNC 1.7.2+deb3 - https://znc.in) |
| 2021-04-19 18:48:51 | → | Pickchea joins (~private@unaffiliated/pickchea) |
| 2021-04-19 18:48:51 | <wroathe> | ski: But trying to explain them one monad at a time I still think leaves people confused about what all of these things have in common |
| 2021-04-19 18:48:58 | → | Guest_70 joins (8a26aed7@138-38-174-215.eduroam.bath.ac.uk) |
| 2021-04-19 18:49:03 | <monochrom> | Yeah too much armchair philosophy out there. |
| 2021-04-19 18:50:00 | <Cale> | I think the examples kind of have to come first though, regardless of whether we mention that they're monads or not |
| 2021-04-19 18:50:17 | <Cale> | You can explain the abstraction without the examples, but it will seem pointless |
| 2021-04-19 18:50:44 | <Cale> | But you *do* actually need to get to the abstraction |
| 2021-04-19 18:50:53 | <MrFantastik> | I think that's the hard part |
| 2021-04-19 18:50:58 | <ski> | "What the hell are Monads?" by Noel Winstanley in 1999-02 at <https://www-users.mat.uni.torun.pl//~fly/materialy/fp/haskell-doc/Monads.html> is probably my favorite initial monad tutorial (also happens to be the first one, attempting to explain monads in general, that's not in a paper) |
| 2021-04-19 18:51:23 | <Guest_70> | Hey everyone, I am trying to install haskell on my Mac OS X El capitan latest version. I get an error message on the second confirmation of pressing enter. Here is the error message: [ Info ] verifying digest of: ghc-8.10.4-x86_64-apple-darwin.tar.xz |
| 2021-04-19 18:51:24 | <Guest_70> | [ Info ] Unpacking: ghc-8.10.4-x86_64-apple-darwin.tar.xz to /var/folders/vb/xw21l2391q90s22qq8qgxh7c0000gp/T/ghcup-ALt2jn |
| 2021-04-19 18:51:24 | <Guest_70> | dyld: lazy symbol binding failed: Symbol not found: _futimens |
| 2021-04-19 18:51:25 | <Guest_70> | Referenced from: /Users/JoeHall/.ghcup/bin/ghcup (which was built for Mac OS X 10.13) |
All times are in UTC.