Jun 21 17:59:01 * DanielYoung (n=quassel@124-171-216-56.dyn.iinet.net.au) has joined #bfpg Jun 21 17:59:03 Hehe Jun 21 17:59:20 hi all Jun 21 17:59:32 * TheColonial (n=OJ@115.64.213.55) has joined #bfpg Jun 21 17:59:44 Evening all. Jun 21 17:59:53 <`Zerax`> 50 seconds till brain melting Jun 21 18:00:08 s/melting/expanding/ I think you mean Jun 21 18:00:23 * toddity (n=toddity@c211-31-28-249.rochd5.qld.optusnet.com.au) has joined #bfpg Jun 21 18:00:48 we'll give it another 5 for the late starters Jun 21 18:00:56 melting implies expanding ;) Jun 21 18:01:05 TonyMorris: seconds or minutes? :p Jun 21 18:00:34 hours Jun 21 18:00:39 to make you regret waking up Jun 21 18:00:42 DanielYoung: not really... you melt ice, and initially it takes up less volumes... Jun 21 18:00:45 medfly: heh Jun 21 18:00:51 I'm glad I came in early - I had it down as 6:30 in my calendar Jun 21 18:01:09 * ivanm notices that for the most part, the "use real names for your nick" suggestion didn't take off... Jun 21 18:01:22 * TheColonial is now known as OliverReeves[OJ] Jun 21 18:01:29 * OliverReeves[OJ] forgot ;) Jun 21 18:01:34 I didn't know Jun 21 18:01:37 * `Zerax` wasn't told Jun 21 18:01:37 For those on linux I just discovered there is also a haskell interpreter called "hugs" Jun 21 18:01:42 * `Zerax` is now known as OliverTaylor Jun 21 18:01:50 GHCi works fine on Linux Jun 21 18:01:58 aha... Jun 21 18:01:59 please stick with ghci :) Jun 21 18:02:00 I don't use my real name online. Jun 21 18:02:06 didn't realise there was that. Jun 21 18:02:09 and hugs used to work on windows, i haven't used it in a long time tho Jun 21 18:02:11 * Woof is now known as VM- Jun 21 18:02:15 * Apocalisp is now known as RunarOli Jun 21 18:02:31 SteveDalton: don't use it, it's old ;-) Jun 21 18:02:36 Yeah - I am just using ghc as instructed tony - I was just messing about with other stuff while I waited - didn't realise there was ghci... don't need hugs now then Jun 21 18:02:44 ok - apt-get remove... :) Jun 21 18:02:45 ghci seems to have a lot more activity around it Jun 21 18:02:46 SteveDalton: hugs devel is not really active anymore afaik Jun 21 18:02:57 OliverReeves[OJ]: well, some activity > no activity ;-) Jun 21 18:03:08 hmm time for one more donut then ;o) Jun 21 18:03:11 right it is gone... ghci all the way :) Jun 21 18:03:14 ivanm: I'm certianly no authority. Hence "seems" :) Jun 21 18:03:21 SteveDalton: good man :) Jun 21 18:03:36 by the way... my Real World Haskell book arrived! WAHOO! Jun 21 18:03:52 I was referring to some old doco that didn't have ghci - recommended hugs for interpreter. Jun 21 18:03:55 OliverReeves[OJ]: my main problem with RWH is how big the errata list is :( Jun 21 18:04:13 bad news is, the stupid Australia Post dude threw it up on the balcony. Resulting in dog-eared corners.. and it being wet coz of the rain :( Jun 21 18:04:14 * VM- is now known as Vin Jun 21 18:04:15 there's a section where the code evaluated to an error (forgot an import), and they talk about the output of their commands :s Jun 21 18:04:25 OliverReeves[OJ]: :o Jun 21 18:04:25 ivanm: true, but hey, it's better than no book at all. Jun 21 18:04:30 where did you get it from? Jun 21 18:04:38 OliverReeves[OJ]: Where did you get it from. Jun 21 18:04:47 If it's Amazon - tell them - they'll send you a new one. Jun 21 18:04:52 * boscop (n=boscop@e181181202.adsl.alicedsl.de) has joined #bfpg Jun 21 18:04:53 SteveDalton: ivanm: yeah, not impressed. Fishpond. But it came via OzPost. Jun 21 18:04:56 www.booko.com.au Jun 21 18:05:06 OliverReeves[OJ]: I got it from fishpond... no problems :s Jun 21 18:05:10 i'm going to have a go at fishpond to see if they can give me another.. but it's the fault of ozpost. Jun 21 18:05:11 BOSCOP Jun 21 18:05:12 You made it Jun 21 18:05:15 yeah i dont blame fishpond. Jun 21 18:05:15 $55, pre-ordered! \o/ Jun 21 18:05:22 Was gonna kill you Jun 21 18:05:28 i blame the idiot delivery guy. obviously has the brains of a wet lettuce. Jun 21 18:05:29 Auspost soaked 3 books of mine... Amazon just sent me out new ones... never asked for old ones back so I dried them out on radiator and gave them to my mates :) Jun 21 18:05:31 >ivanm< http://projects.tmorris.net/public/haskell-parsers/artifacts/0.9/chunk-html/index.html Jun 21 18:05:44 SteveDalton: Yeah we really need amazon.com.au :) Jun 21 18:05:48 Vin: how often do you change your nick? Jun 21 18:05:50 ok get started then? Jun 21 18:05:51 Yep. Jun 21 18:05:57 yup! let's go. Jun 21 18:06:00 did it just start? Jun 21 18:06:02 boscop: It was suggested that we use real names here Jun 21 18:06:13 delivery guys here send things in closed plastic containers even though it is unlikely it'll rain Jun 21 18:06:19 boscop: /nick Foo Jun 21 18:06:21 OK, so what we are going to do is write our own library for parsing Jun 21 18:06:42 we will do it incrementally stopping for any questions along the way Jun 21 18:06:56 ivanm can also help out with questions and so can Cale but he doesn't seem to be around at the moment Jun 21 18:07:18 feel free to /msg me (if I'm still around, might be going off for dinner soonish) if you don't want to ask everyone Jun 21 18:07:24 s/everyone/publically/ Jun 21 18:07:33 I have some slides here that I will make available afterward -- which includes the final Haskell source file -- I have also written the parsing library in Scala and Java for reference Jun 21 18:07:45 type 'q' at any time there is a question so we know to stop and await a question Jun 21 18:08:00 you will need a text editor and a ghci command prompt Jun 21 18:08:05 let's go Jun 21 18:08:34 http://video.java.no/2009/tony/docbook/01/MyParser.hs Jun 21 18:08:36 ok Jun 21 18:08:47 enter that into a text file called MyParser.hs Jun 21 18:08:54 then at the ghci prompt type Jun 21 18:08:58 :load MyParser.hs Jun 21 18:09:03 the prompt should then read Jun 21 18:09:07 *MyParser> Jun 21 18:09:46 * toddity has quit () Jun 21 18:10:01 I will assume we are all good in 10 seconds Jun 21 18:10:21 ok, so the next thing we will do is define what a parser is Jun 21 18:10:26 A parser is a function that accepts an input String and either fails or produces a value and the remaining input String. Jun 21 18:10:57 http://video.java.no/2009/tony/docbook/02/MyParser.hs add this to your source file Jun 21 18:11:00 then at ghci type Jun 21 18:11:01 * medfly (n=lio@unaffiliated/medfly) has left #bfpg ("Leaving") Jun 21 18:11:03 :reload Jun 21 18:11:25 examine the type of the 'parse' function that we just defined Jun 21 18:11:30 you can do this by typing Jun 21 18:11:32 :type parse Jun 21 18:11:48 parse accepts a parser and input and either fails or produces a value and the remaining input. Jun 21 18:11:59 * MitchellRiley (n=user@d58-111-182-36.rdl7.qld.optusnet.com.au) has joined #bfpg Jun 21 18:12:27 10 seconds Jun 21 18:12:53 we see that when our Parser fails, it doesn't produce any error message or a position of failure Jun 21 18:12:59 we are doing this to keep the exercise simple Jun 21 18:13:04 * mvr has quit (Client Quit) Jun 21 18:13:05 let's define our first parser Jun 21 18:13:13 http://video.java.no/2009/tony/docbook/03/MyParser.hs Jun 21 18:13:36 this parser consumes no input (by returning the input) and always produces the given value Jun 21 18:13:56 if you are used to OO-like languages, the data Parser declaration is like an interface, and value is like an instance of that interface Jun 21 18:13:58 * __andrew__ (n=andrew@124-171-175-253.dyn.iinet.net.au) has joined #bfpg Jun 21 18:13:59 :q this is with "data" right? Jun 21 18:14:12 SteveDalton, with "data"? I'm not sure what you mean Jun 21 18:14:27 within the {} I meant - sorry Jun 21 18:14:31 I got it. Jun 21 18:14:36 no sorry, we are appending to the file as we go Jun 21 18:14:47 ok. got you Jun 21 18:15:08 http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6101#a6101 our file should look like this Jun 21 18:15:15 we are :reloading at ghci as we go Jun 21 18:15:25 __andrew__, want to join? Jun 21 18:15:35 <__andrew__> hello Jun 21 18:15:38 <__andrew__> yeah just catching up Jun 21 18:16:05 __andrew__, add this to a source file called MyParser.hs http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6101#a6101 and load it into ghci using :load MyParser.hs Jun 21 18:16:17 * Twey (n=Twey@unaffiliated/twey) has joined #bfpg Jun 21 18:16:28 <__andrew__> ok Jun 21 18:16:45 so we might now experiment with our two functions, value and parse Jun 21 18:16:50 :type parse (value "boo") Jun 21 18:16:58 parse (value 7) "input" Jun 21 18:17:03 parse (value "boo") "input" Jun 21 18:17:14 note that the input remains unaltered and the given value is also returned Jun 21 18:17:25 let us now write another function which is a parser that always fails Jun 21 18:17:32 http://video.java.no/2009/tony/docbook/04/MyParser.hs Jun 21 18:17:47 this parser is not particularly interesting but we will use it later on Jun 21 18:18:19 the underscore denotes that we are ignoring the input, since we are always failing, regardless of the input Jun 21 18:18:42 Let's create a parser that consumes one character and produces that character, unless the input is empty, in which case fail. Jun 21 18:18:55 http://video.java.no/2009/tony/docbook/05/MyParser.hs Jun 21 18:19:10 Experiment with the character parser Jun 21 18:19:15 :type parse character Jun 21 18:19:19 parse character "abc" Jun 21 18:19:24 parse character "" Jun 21 18:19:53 notice that the parser fails when there is no more input, otherwise, one character is produced and the input moves along one character Jun 21 18:20:21 Write a function that accepts two parsers and returns a parser that tries the first parser for success. If that parser fails, try the second parser. Jun 21 18:20:30 we will call this 'the choice parser' Jun 21 18:20:36 http://video.java.no/2009/tony/docbook/06/MyParser.hs Jun 21 18:20:52 there may be some new syntactic surprises there -- questions? Jun 21 18:21:21 experiment with the choice parser Jun 21 18:21:26 the ||| parser will have a default left fixity Jun 21 18:21:34 *MyParser> let p = character ||| value 'x' in parse p "abc" Jun 21 18:22:12 *MyParser> let p = character ||| value 'x' in parse p "" Jun 21 18:22:18 *MyParser> let p = character ||| failed in parse p "abc" Jun 21 18:22:23 *MyParser> let p = character ||| failed in parse p "" Jun 21 18:22:26 questions? Jun 21 18:22:39 :q Where is "{...}" of data Parser a = P { ... } documented? Or what does it mean? Jun 21 18:22:55 AdrianPronk: it creates a record data structure Jun 21 18:22:57 that's called record syntax Jun 21 18:23:17 it is a bit like naming a method of a class in OO Jun 21 18:23:21 it gives you functions to pull out individual functions for free Jun 21 18:23:33 and you can also use them as shortcuts to change part of a data structure Jun 21 18:23:41 observe the type of parse :: Parser a -> String -> Maybe (String, a) Jun 21 18:23:46 they become more useful for larger data structures (e.g. 10 fields) Jun 21 18:23:59 AdrianPronk, ok? Jun 21 18:24:45 Does it define an implemantion (for parse in this case)? Jun 21 18:24:46 It essentially means that you have a P (String -> Maybe (String, a)), but you get a function parse :: Parser -> String -> Maybe (String, a) for free, as well as some magic syntax for pattern-matching and updating individual fields Jun 21 18:24:50 AdrianPronk: no Jun 21 18:24:51 Yes Jun 21 18:24:56 heh Jun 21 18:25:10 it defines what the type parse must take Jun 21 18:25:12 AdrianPronk, no, it doesn't -- each of our functions thereafter define implementations Jun 21 18:25:21 actual implementations are done with P ( \s -> ... ) Jun 21 18:25:22 * Twey tilts his head. Jun 21 18:25:32 AdrianPronk, it is very much like (Java): interface Parser { Pair parse(String s); } Jun 21 18:26:04 Sorry, you'll have to rephrase the question. I took it to mean you were asking about whether the getter function parse had to be defined manually later on, to which the answer is no. Jun 21 18:26:21 Twey: nah, he meant does parse have a default implementation (I think) Jun 21 18:26:22 so P (\s -> ... ) defines parse for this case? Jun 21 18:26:28 AdrianPronk: yes Jun 21 18:26:32 The function parse gets defined automatically; the function that we insert into the field doesn't Jun 21 18:26:43 Is there some kind of positional correspondence? Jun 21 18:26:46 AdrianPronk, precisely Jun 21 18:26:50 well, parse returns the (\s -> ...) function Jun 21 18:27:10 AdrianPronk, the P constructor must take a function of the correct type (or you will receive a type error) Jun 21 18:27:30 AdrianPronk, but if the data type had more than one field, then they must appear in the order that they are defined Jun 21 18:27:31 ok, press on. I'll see how I go... Jun 21 18:27:51 consider: data Person = Per Int String Jun 21 18:27:59 then you must Per anInt aString Jun 21 18:28:26 if a Parser produces values of type 'a' and we have a function a -> b we can get a Parser that produces values of type 'b' Jun 21 18:28:37 Write a function that accepts a parser and a function from its produced value to another value to return a parser that potentially produces that value. We will see later why this function is useful. Jun 21 18:28:45 http://video.java.no/2009/tony/docbook/07/MyParser.hs Jun 21 18:28:51 * OliverReeves[OJ] is now known as OliverReeves[Bac Jun 21 18:29:00 * OliverReeves[Bac is now known as OliverReeves[Brb Jun 21 18:29:16 Experiment with the mapping parser Jun 21 18:29:20 *MyParser> let p = mapParser character toUpper in parse p "abc" Jun 21 18:29:23 note that this is an instance of a "higher-order function", that is we have a function that takes a function as a parameter Jun 21 18:29:29 *MyParser> let p = mapParser character toUpper in parse p "" Jun 21 18:29:58 notice here that when the parser produces a character value, it has converted it to upper-case from the input Jun 21 18:30:45 Write a function that accepts a parser and a function from its produced value to another parser producing values of some type and returns a parser producing values of that same type. Again, we will see later why this function is useful. Jun 21 18:30:53 Parser a -> (a -> Parser b) -> Parser b Jun 21 18:31:12 http://video.java.no/2009/tony/docbook/08/MyParser.hs Jun 21 18:31:38 Experiment with the binding parser Jun 21 18:31:42 *MyParser> let p = bindParser character (\c -> if isUpper c then value c else failed) in parse p "" Jun 21 18:31:47 *MyParser> let p = bindParser character (\c -> if isUpper c then value c else failed) in parse p "abc" Jun 21 18:31:53 *MyParser> let p = bindParser character (\c -> if isUpper c then value c else failed) in parse p "Abc" Jun 21 18:32:24 I hope I haven't lost anyone :) Jun 21 18:33:03 this all makes perfect sense to everyone so far? Jun 21 18:33:06 do you have the complete source file up until this point? Jun 21 18:33:07 does everyone understand TonyMorris, or -- apart from AdrianPronk -- too shy to ask questions? :p Jun 21 18:33:37 <__andrew__> i think it's good so far Jun 21 18:33:38 koala_man, http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6101#a6102 Jun 21 18:33:39 * juhp is following as fast as he can :) Jun 21 18:33:42 * AdrianPr` (n=user@203-214-84-239.dyn.iinet.net.au) has joined #bfpg Jun 21 18:33:42 * AdrianPronk__ (n=AdrianPr@203-214-84-239.dyn.iinet.net.au) has joined #bfpg Jun 21 18:33:52 great, thanks Jun 21 18:33:55 juhp, shall I slow down? Jun 21 18:34:07 TonyMorris: not yet :) Jun 21 18:34:13 we might do a bit more and take a 5 minute break to have a look and maybe form some questions Jun 21 18:34:24 TonyMorris: maybe give a recap of what we've done so far? Jun 21 18:34:32 yes Jun 21 18:34:37 That'd be good Jun 21 18:34:52 yep, just trying to keep up :) Jun 21 18:34:52 OK, so far we have defined what a parser is with a data declaration Jun 21 18:35:03 then we have written some parser values and functions over parsers Jun 21 18:35:09 note that Parser is just a wrapper around a parsing function Jun 21 18:35:24 we have written a parser that takes a value and input and returns that value and input unchanged Jun 21 18:35:33 we have written a parser that always fails regardless of the input Jun 21 18:35:47 Hi Tony - you lost me a while back... I am going to do some more reading tomorrow and come back to the transcript and have another go... just go on without me... thanks anyway - appreciate you making all this effort. :) Jun 21 18:35:48 we have written a parser that consumes a single character, unless there isn't one, in which case, it fails Jun 21 18:36:10 we have written a parser that takes two parsers, tries the first one, if it fails, tries the second (it might fail too) Jun 21 18:36:26 we have written a function to map a function across the values produced by a parser Jun 21 18:36:28 :q Jun 21 18:36:38 we have written a function that binds a function across a parser Jun 21 18:36:41 don't quite get this syntax: v@(Just _) -> v Jun 21 18:36:49 toddity, that is called as-pattern syntax Jun 21 18:37:02 so 'v' is the name of the entire expression(Just _) Jun 21 18:37:19 i.e. it is the value that is being matched on (p1 s) Jun 21 18:37:28 and the underscore denotes that we don't care about the value Jun 21 18:37:41 all we care about is that (p1 s) produced a successful result (Just) Jun 21 18:37:56 in which case, return that entire result (Just theResult) Jun 21 18:37:59 which is named 'v' **** BEGIN LOGGING AT Sun Jun 21 18:45:12 2009 Jun 21 18:45:12 * Now talking on #bfpg Jun 21 18:45:12 * Topic for #bfpg is: Brisbane Functional Programming Group http://www.meetup.com/Brisbane-Functional-Programming-Group-BFG/ Next meeting: http://www.meetup.com/Brisbane-Functional-Programming-Group-BFG/calendar/10652263/ | Special thanks to scalabin, the Norwegian Scala group for hosting presentation material Jun 21 18:45:12 * Topic for #bfpg set by dibblego at Sun Jun 21 10:53:12 2009 Jun 21 18:45:13 * Received a CTCP VERSION from freenode-connect Jun 21 18:45:17 * dobblego sets mode -e dobblego Jun 21 18:45:17 * You are now known as TonyMorris Jun 21 18:45:18 -NickServ- This nickname is registered. Please choose a different nickname, or identify via /msg NickServ identify . Jun 21 18:45:21 ivanm: Operation timed out xD Jun 21 18:45:24 \o/ Jun 21 18:45:28 >NickServ< identify **** Jun 21 18:45:29 TonyMorris is back! Jun 21 18:45:29 -NickServ- You are now identified for TonyMorris. Jun 21 18:45:29 * services. sets mode +e TonyMorris Jun 21 18:45:30 how efficient is this sort of parsing compared to LR parsers? Jun 21 18:45:40 koala_man: don't know what LR parsers are, sorry Jun 21 18:45:53 and I'm not sure in which direction TonyMorris is going to take this (backtracking parsers, etc.) Jun 21 18:46:12 it can be very efficient in a lazy language Jun 21 18:46:14 It is an LR parser, so far Jun 21 18:46:19 * JustinNShield (n=miguel_b@ppp118-208-121-143.lns4.bne4.internode.on.net) has joined #bfpg Jun 21 18:46:27 toddity, that is called as-pattern syntax Jun 21 18:46:27 so 'v' is the name of the entire expression(Just _) Jun 21 18:46:27 i.e. it is the value that is being matched on (p1 s) Jun 21 18:46:27 and the underscore denotes that we don't care about the value Jun 21 18:46:33 all we care about is that (p1 s) produced a successful result (Just) Jun 21 18:46:33 in which case, return that entire result (Just theResult) Jun 21 18:46:33 which is named 'v' Jun 21 18:46:40 Python interface unloaded Jun 21 18:46:40 Tcl interface unloaded **** ENDING LOGGING AT Sun Jun 21 18:46:40 2009 Jun 21 18:47:10 moving on then? Jun 21 18:47:12 It's just a different way of structuring it Jun 21 18:47:22 many thanks, all good. Jun 21 18:47:50 so next we'll define a function similar to bindParser, except you don't pass it a function -- instead pass it another parser which is always returned Jun 21 18:47:59 This will be useful for example, when we wish for a parser to consume white-space but not do anything with that white-space. Jun 21 18:48:07 http://video.java.no/2009/tony/docbook/09/MyParser.hs Jun 21 18:48:41 Write a function that accepts a list of parsers and produces a parser of lists by calling bindParser and mapParser as you go along the list. Jun 21 18:48:51 http://video.java.no/2009/tony/docbook/10/MyParser.hs Jun 21 18:50:16 *MyParser> let p = sequenceParser [character, value 'b', character] in parse p "" Jun 21 18:50:21 *MyParser> let p = sequenceParser [character, value 'b', character] in parse p "a" Jun 21 18:50:25 *MyParser> let p = sequenceParser [character, value 'b', character] in parse p "ab" Jun 21 18:50:30 *MyParser> let p = sequenceParser [character, value 'b', character] in parse p "abc" Jun 21 18:50:43 we see here that we pass a list of parsers and get back a parser that produces a list Jun 21 18:50:52 * AdrianPronk has quit (Connection timed out) Jun 21 18:50:57 Write a function that accepts an integer (n) and a parser and returns a parser that binds 'n' times. We can do this by using the library function replicate. Jun 21 18:50:58 * AdrianPronk_ has quit (Read error: 110 (Connection timed out)) Jun 21 18:51:08 * AdrianPronk__ is now known as AdrianPronk Jun 21 18:51:15 http://video.java.no/2009/tony/docbook/11/MyParser.hs Jun 21 18:51:30 just so you can all see what replicate does: Jun 21 18:51:38 > replicate 10 "hi" Jun 21 18:51:40 ["hi","hi","hi","hi","hi","hi","hi","hi","hi","hi"] Jun 21 18:52:01 yes, so replicate n always produces a list with the length n Jun 21 18:52:18 so our returned parser from thisMany will always produce a list of the given length Jun 21 18:52:37 this might be useful, for example, we want to parse exactly 5 characters Jun 21 18:52:44 then: thisMany 5 character Jun 21 18:52:49 how to use >>> ? Jun 21 18:53:34 you mean, an example use? Jun 21 18:53:51 juhp: parser1 >>> parser2 Jun 21 18:53:52 parse (character >>> value "foo") "abc" Jun 21 18:54:08 TonyMorris: yes Jun 21 18:54:11 (which is the same as writing (>>>) parser1 parser2) Jun 21 18:54:20 parse (thisMany 5 character) "123456" Jun 21 18:54:33 Operators in Haskell are just normal functions that can be written in between their first two arguments. Jun 21 18:54:43 thanks Jun 21 18:54:54 *MyParser> parse (character >>> character) "abc" Jun 21 18:54:54 Just ("c",'b') Jun 21 18:55:02 notice that the 'a' is dropped (ignored) Jun 21 18:55:03 -> koala_man Jun 21 18:55:04 The magic is triggered by the identifier consisting entirely of non-alphabetical characters Jun 21 18:55:32 ah Jun 21 18:55:36 * dibblego has quit (Read error: 110 (Connection timed out)) Jun 21 18:55:39 which aren't (), etc. Jun 21 18:55:41 ok, a few more mundane details to go, until we get into the good bit :) Jun 21 18:55:44 * Disconnected (Invalid argument). **** ENDING LOGGING AT Sun Jun 21 18:55:44 2009 Jun 21 18:55:45 Aye. Jun 21 18:55:52 (there are some reserved symbols) Jun 21 18:56:04 we are now going to write two functions, which depend on each other Jun 21 18:56:07 * dibblego (n=nobody@220-245-107-64.static.tpgi.com.au) has joined #bfpg **** BEGIN LOGGING AT Sun Jun 21 18:56:09 2009 Jun 21 18:56:20 One takes a parser and applies itself zero or many times (list) and the other takes a parser and applies itself one or many times (many1). These functions are useful for such things as parsing white-space, where we may take a parser of a single white-space character and obtain a parser of e.g. one or many white-space characters. Jun 21 18:56:29 http://video.java.no/2009/tony/docbook/12/MyParser.hs Jun 21 18:56:32 * AdrianPr` is now known as AdrianPronk_ Jun 21 18:56:35 co-recursive functions! \o/ Jun 21 18:57:07 we want brains to expand, right? :) Jun 21 18:57:14 definitely! Jun 21 18:57:15 always Jun 21 18:57:16 Probably better to stick with calling them ‘mutually recursive’ to avoid confusion :-P Jun 21 18:57:31 Twey: awwww.... that so no comanads, etc.? :p Jun 21 18:57:36 s/that// Jun 21 18:57:43 Hehe Jun 21 18:57:51 *MyParser> let p = many1 character in parse p "" Jun 21 18:58:00 notice that this parse fails Jun 21 18:58:05 *MyParser> let p = list character in parse p "" Jun 21 18:58:12 this one succeeds but has exhausted input Jun 21 18:58:18 *MyParser> let p = many1 character in parse p "abc" Jun 21 18:58:23 *MyParser> let p = list character in parse p "abc" Jun 21 18:59:01 everyone on track? Jun 21 18:59:11 I think so Jun 21 18:59:16 Clear as mud! Jun 21 18:59:24 http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6104#a6104 here is where we are up to Jun 21 18:59:39 Write a parser that consumes a character (or fails if there isn't one) and ensures that character meets a given predicate. We might also use this parser to write another parser (is) that parses a specific character. Jun 21 18:59:50 http://video.java.no/2009/tony/docbook/13/MyParser.hs Jun 21 19:00:02 Experiment with these parsers Jun 21 19:00:05 list -> parse as manay as you can; many1 -> parse at least 1, and then as many as you can Jun 21 19:00:23 let p = satisfy isUpper in parse p "" Jun 21 19:00:26 * OliverReeves[Brb is now known as OliverReeves Jun 21 19:00:31 let p = satisfy isUpper in parse p "abc" Jun 21 19:00:52 these two fail since there is not a first character that matches the predicate (isUpper) Jun 21 19:00:57 *MyParser> let p = satisfy isUpper in parse p "Abc" Jun 21 19:00:59 note that in is, (== c) is known as a _section_, as we've filled in one side of the operator == Jun 21 19:01:00 this one succeeds Jun 21 19:01:21 *MyParser> let p = is 'a' in parse p "" Jun 21 19:01:33 fails since no character Jun 21 19:01:34 *MyParser> let p = is 'a' in parse p "abc" Jun 21 19:01:41 succeeds and consumes 'a' Jun 21 19:01:46 *MyParser> let p = is 'a' in parse p "xbc" Jun 21 19:01:54 fails since not 'a' to consume Jun 21 19:02:34 Let us now write a bunch of parsers that use satisfy and apply the predicate. Jun 21 19:02:40 http://video.java.no/2009/tony/docbook/14/MyParser.hs\ Jun 21 19:02:41 http://video.java.no/2009/tony/docbook/14/MyParser.hs Jun 21 19:02:58 * MatCallan (n=irchon@114.73.243.80) has joined #bfpg Jun 21 19:03:08 I will give 3 or 4 minutes to consume at this point Jun 21 19:03:42 note that isDigit does '0'..'9' Jun 21 19:03:50 :q Can you create a section for multi-parameter alphabetic functions so that the arbitray parameters are pre-specified? Jun 21 19:03:52 there are other functions that do other types of "numeric" characters Jun 21 19:04:05 AdrianPronk: Yes and no Jun 21 19:04:12 e.g. isNumber also works on roman numerals Jun 21 19:04:35 AdrianPronk: You'd use instead a technique called ‘currying’ Jun 21 19:04:55 ok, I'll read about currying offline Jun 21 19:05:07 * Twey nods. Jun 21 19:05:10 ivanm: Can you give an example of using isNumber with a roman numeral? Jun 21 19:05:19 It may be a bit in-depth and/or confusing to get into here. Jun 21 19:05:29 Vin: no ;-) Jun 21 19:05:38 I'm reading off the documentation ;-) Jun 21 19:06:03 and I have no idea how it reads Roman numerals in :s Jun 21 19:06:11 Experiment with some of these parsers Jun 21 19:06:14 parse upper "" Jun 21 19:06:16 this fails Jun 21 19:06:18 Okay. isNumber 'v' doesn't work. But nvm Jun 21 19:06:23 parse upper "a" Jun 21 19:06:26 this also fails Jun 21 19:06:31 parse upper "A" Jun 21 19:06:34 Where's this isNumber function, sorry? Jun 21 19:06:37 this succeeds and consume input Jun 21 19:06:42 >lambdabot< @type isNumber Jun 21 19:06:49 @type isNumber Jun 21 19:06:51 Char -> Bool Jun 21 19:06:52 Vin: it uses unicode codpoints, I think Jun 21 19:06:54 Twey: Data.Char Jun 21 19:06:57 Ah Jun 21 19:07:00 @index isNumber Jun 21 19:07:00 ivanm: Oh, okay Jun 21 19:07:01 bzzt Jun 21 19:07:06 @src isNumber Jun 21 19:07:06 Source not found. Have you considered trying to match wits with a rutabaga? Jun 21 19:07:07 *codepoints Jun 21 19:07:23 Twey: it does some weird parsing thingy using enums (I'm reading the source) Jun 21 19:07:29 @hoogle isNumber Jun 21 19:07:29 Data.Char isNumber :: Char -> Bool Jun 21 19:07:32 Doesn't seem to do Roman numerals. Jun 21 19:07:36 let p = list digit in parse p "79abc" Jun 21 19:07:50 observe that this parser reads off and produces the first two digits Jun 21 19:08:06 So far we have constructed a small library of parsers. Some of these parsers are constructed from other parsers. This notion of constructing units of work from other, smaller units of work is the essence of functional programming. Jun 21 19:08:19 Does it scale? Jun 21 19:08:25 Can we write even more higher-level parsers with our library by gluing parsers? Jun 21 19:08:37 Suppose we have a data structure to represent a person. The person data structure has these attributes: Jun 21 19:08:41 Age: positive integer Jun 21 19:08:45 First Name: non-empty string that starts with a capital letter Jun 21 19:08:50 Surname: string that starts with a capital letter and is followed by 5 or more lower-case letters Jun 21 19:08:54 Gender: character that must be 'm' or 'f' Jun 21 19:08:57 I think I missed something, where is "digit"? Jun 21 19:09:00 Phone: string of digits, dots or hyphens but must start with a digit and end with a hash (#) Jun 21 19:09:06 Vin, http://video.java.no/2009/tony/docbook/14/MyParser.hs Jun 21 19:09:20 Oops, didn't reload Jun 21 19:09:22 Right Jun 21 19:09:31 http://video.java.no/2009/tony/docbook/15/MyParser.hs Jun 21 19:09:37 here is our Person data type declaration Jun 21 19:09:57 "deriving Show" is a bit like saying (Java) "generate an automate toString" Jun 21 19:10:15 deriving is a keyword Jun 21 19:10:23 the Show class (which has the show function) is generally used to print out the "code" of that datatype Jun 21 19:10:31 you normally don't use it for pretty-printing Jun 21 19:10:39 the reverse is the read function in the Read class Jun 21 19:10:45 (you can derive Read as well) Jun 21 19:10:57 notice that the constructor and data type have the same name (Person), though they are separate things Jun 21 19:11:19 so we pass Person 5 arguments to produce a value of type Person Jun 21 19:11:40 anyone want to take a punt at how the parser for parsing the Person's age might look? Jun 21 19:11:51 (using our library) Jun 21 19:11:53 natural Jun 21 19:12:02 * TonyMorris hands koala_man a cookie Jun 21 19:12:10 http://video.java.no/2009/tony/docbook/16/MyParser.hs Jun 21 19:12:33 how about parsing the first name? Jun 21 19:12:42 non-empty string that starts with a capital letter Jun 21 19:13:17 http://video.java.no/2009/tony/docbook/17/MyParser.hs Jun 21 19:13:31 we are "gluing" parsers together using bindParser and mapParser Jun 21 19:13:50 These two functions are turning out to be quite helpful. Jun 21 19:13:55 surname parser? Jun 21 19:14:03 string that starts with a capital letter and is followed by 5 or more lower-case letters Jun 21 19:14:10 why 5? Jun 21 19:14:15 arbitrary Jun 21 19:14:20 ok ;) Jun 21 19:14:22 just to confuse us and show off the parsing functions ;-) Jun 21 19:14:22 because they are the rules for this particular Person Jun 21 19:14:38 (obviously, Mr Ng isn't going to be pleased with us if we use these rules for the ATO or something...) Jun 21 19:14:48 my surname is a capital followed by 4 lower-case letters :( Jun 21 19:14:56 Heh Jun 21 19:14:59 koala_man: I'm sorry, but you're not a Person then Jun 21 19:15:00 ;-) Jun 21 19:15:11 for surname, we might use upper, (thisMany 5 lower) and (list lower) and glue them all together Jun 21 19:15:14 koala_man: you'll have to change your name :) Jun 21 19:15:20 I'll just make a data Koala Jun 21 19:15:21 My last name is a capital followed by only 3 letters Jun 21 19:15:33 how will we glue them together? Jun 21 19:15:44 http://video.java.no/2009/tony/docbook/18/MyParser.hs Jun 21 19:15:47 magic! Jun 21 19:15:54 bindParser/mapParser again Jun 21 19:16:07 any guesses for ageParser? Jun 21 19:16:11 character that must be 'm' or 'f' Jun 21 19:16:20 TonyMorris: "ageParser"? Jun 21 19:16:28 you mean genderParser? Jun 21 19:16:31 oops yes Jun 21 19:16:38 genderParser character that must be 'm' or 'f' Jun 21 19:16:39 is 'm' ||| is 'f' Jun 21 19:16:49 correct Jun 21 19:16:55 http://video.java.no/2009/tony/docbook/19/MyParser.hs Jun 21 19:16:58 * ivanm gives koala_man another of TonyMorris's cookies Jun 21 19:17:18 the phone number is quite complicated, we'll split it for simplicity Jun 21 19:17:34 first we will parse the phone number body (without the #) Jun 21 19:17:56 http://video.java.no/2009/tony/docbook/20/MyParser.hs Jun 21 19:18:25 then we will use phoneBodyParser to glue together to create phoneParser to include the hash Jun 21 19:18:36 http://video.java.no/2009/tony/docbook/21/MyParser.hs Jun 21 19:18:41 using bindParser/mapParser again of course Jun 21 19:18:55 questions? 2 minutes Jun 21 19:19:12 you might like to experiment with some of our parsers Jun 21 19:19:16 (after you :reload of course) Jun 21 19:19:21 *MyParser> parse firstNameParser "" Jun 21 19:19:25 fails since no input Jun 21 19:19:29 *MyParser> parse firstNameParser "fred" Jun 21 19:19:36 fails since no upper-case character first Jun 21 19:19:40 *MyParser> parse firstNameParser "Fred" Jun 21 19:19:41 succeeds Jun 21 19:19:51 *MyParser> parse surnameParser "Fred" Jun 21 19:20:00 fails since not 5 characters after the first Jun 21 19:20:04 *MyParser> parse surnameParser "Frederick" Jun 21 19:20:10 there's a pattern here. we keep gluing together functions by parsing x elements and returning a string of the concatenated results. can't we capitalize on that? Jun 21 19:20:48 you mean gluing together x parsers? Jun 21 19:21:00 yes, by concatenating their results Jun 21 19:21:20 yes we can capitalise on that, but we won't be covering that today Jun 21 19:21:24 koala_man: do you mean sequenceParser? Jun 21 19:22:16 there are various ways of capitalising on that in fact, with various trade offs Jun 21 19:22:55 *MyParser> parse phoneParser "123-456.789#" Jun 21 19:23:03 So we have parsers for the components of a Person. But we need a parser for a person. How can we get one of those? Jun 21 19:23:12 any ideas? Jun 21 19:23:24 * ivanm quite firmly keeps his mouth shut Jun 21 19:23:34 glue? Jun 21 19:23:43 sequenceParser with each of those property parsers? Jun 21 19:23:47 I was thinking staples Jun 21 19:24:01 sequenceParser takes a list of parsers of all the same type Jun 21 19:24:06 we won't be able to use that here Jun 21 19:24:09 righto Jun 21 19:24:15 since we have: Parser Int, Parser String, etc. Jun 21 19:24:22 yup, gotcha Jun 21 19:24:34 <__andrew__> Parser Person? Jun 21 19:24:34 so in effect, we have to do the sequenceParser stuff by hand Jun 21 19:24:35 when we have different types like that, we have been gluing them together with: Jun 21 19:24:39 don't forget spaces though Jun 21 19:24:49 yes, we need to produce a Parser Person from the parsers we have just written Jun 21 19:24:58 yes including spaces (which we have in our library) Jun 21 19:25:10 our glue Jun 21 19:25:12 bindParser and mapParser (of course!). Jun 21 19:25:25 so bind age, then space, then first name, then space...etc.. Jun 21 19:25:28 http://video.java.no/2009/tony/docbook/22/MyParser.hs Jun 21 19:25:29 yes! Jun 21 19:25:36 woot :) Jun 21 19:25:44 have a play with that parser Jun 21 19:25:49 parse personParser1 "" Jun 21 19:25:51 fails Jun 21 19:25:56 parse personParser1 "123 Fred Clarkson m 123-456.789#" Jun 21 19:26:06 parse personParser1 "123 Fred Clarkson m 123-456.789# the rest of the input" Jun 21 19:26:13 parse personParser1 "123 Fred Clark m 123-456.789# the rest of the input" Jun 21 19:26:45 We have advanced quite far ahead of what we do with traditional languages. We have glued smaller parts to make larger parts, then glued those larger parts to make even larger parts again. Jun 21 19:26:59 So what with this bindParser and mapParser business? They seem rather fundamental. Can we somehow remove the noise to make them easier to use? Jun 21 19:27:02 It works! Jun 21 19:27:09 very nifty Jun 21 19:27:17 try doing that in C#... Jun 21 19:27:18 I might wait a minute so you can play with that parser Jun 21 19:27:27 OliverReeves, I did it Jun 21 19:27:38 (wait until I show you the Java) Jun 21 19:27:40 i'm not goign to say it's impossible, but it certainly isn't that smple. Jun 21 19:27:50 so how about this glue? Jun 21 19:27:51 i've done something similar in C++... it's not pretty. Jun 21 19:28:12 it is very fundamental -- so much so that both Haskell and Scala have a syntactic notation to get rid of it Jun 21 19:28:22 Haskell has do notation to take care of this pattern for us, since it occurs all over the place, not just parsers. Jun 21 19:28:26 First we must implement a type-class: Jun 21 19:28:32 http://video.java.no/2009/tony/docbook/23/MyParser.hs Jun 21 19:28:46 there's that word! Jun 21 19:29:02 http://video.java.no/2009/tony/docbook/24/MyParser.hs Jun 21 19:29:08 now look at our parser! Jun 21 19:29:24 no!!! not that word!!! Jun 21 19:29:27 TonyMorris: happy? :p Jun 21 19:29:29 experiment with that parser Jun 21 19:30:06 beautiful :) Jun 21 19:30:08 oh my, it works just like the first one, only it's all sweet and sugary in syntax! Jun 21 19:30:12 note that with do-notation, we never explicitly say what to do if a parse fails Jun 21 19:30:22 that's because as soon as one of them fail, the whole thing fails Jun 21 19:30:25 q: Will "do" only work in the presence of something declared using the built-in "Monad" ? Jun 21 19:30:42 AdrianPronk, correct -- without that type-class declaration you receive a type error Jun 21 19:31:02 AdrianPronk, however, alluding to koala_man's question, there are even nicer ways again Jun 21 19:31:16 here is how your completed source file should look http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6106#a6106 Jun 21 19:31:18 * MatCallan has quit (Connection timed out) Jun 21 19:31:49 here is same in Scala http://paste.pocoo.org/show/124285/ Jun 21 19:31:55 and, wait for it.... Jun 21 19:32:05 with some library support propping it up Jun 21 19:32:15 I give you the same again in... Jun 21 19:32:18 Java! http://paste.pocoo.org/show/124286/ Jun 21 19:32:29 beware, dont click on the java version if you're nearing the end of your bandwidtch quota :) Jun 21 19:32:32 (note that personParser2 is not a possibility) Jun 21 19:32:45 OliverReeves: heh Jun 21 19:32:46 @go typeclassopedia Jun 21 19:32:47 http://byorgey.wordpress.com/2009/02/16/the-typeclassopedia-request-for-feedback/ Jun 21 19:32:47 Title: The Typeclassopedia — request for feedback « blog :: Brent -> [String] Jun 21 19:32:54 ^^ if you're interested in what makes a monad a monad, have a look here Jun 21 19:33:33 so that's all everyone -- I will upload the presentation material, which includes everything we just did to the BFPG meetup website Jun 21 19:33:43 (actually, it's uploading now) Jun 21 19:33:45 love ya work Tony, thanks for that. Jun 21 19:33:59 http://files.meetup.com/1443989/haskell-parsers.tar.gz Jun 21 19:34:12 I will also upload this IRC transcript Jun 21 19:34:17 any questions? Jun 21 19:34:18 there are _heaps_ of different haskell parsing libs Jun 21 19:34:24 most of which act similarly to all this Jun 21 19:34:31 parsec (as TonyMorris mentioned), polyparse, etc. Jun 21 19:34:39 oh yes, this library has been implemented for more industrial strength parsing Jun 21 19:34:42 e.g. Parsec Jun 21 19:34:57 for example, I maintain a library that uses polyparse to parse graphviz's Dot language Jun 21 19:35:12 i have to run...thanks heaps tony and others, this was very cool Jun 21 19:35:16 ok bye Jun 21 19:35:18 :q Can someone post this full transcript? I missed a bit near the beginning. Jun 21 19:35:21 * DanielYoung has quit ("must eat") Jun 21 19:35:30 I guess this would be a paradigm observation... Would you say that functional programming is more of a bottom up approach to design where by you are extending the language to fit your needs. From a top down approach? Jun 21 19:35:31 AdrianPronk, I will Jun 21 19:35:39 JustinNShield: yes Jun 21 19:35:49 in FP, you usually do lots of little functions and glue them together Jun 21 19:36:19 Although you can do this paraidgm in almost any language. Would you say it's easier in a fp language? Jun 21 19:36:27 much easier to glue together, yes Jun 21 19:36:34 especially when you glue functions together Jun 21 19:36:43 e.g. how would you write (.) in Java? Jun 21 19:36:45 @src (.) Jun 21 19:36:46 (f . g) x = f (g x) Jun 21 19:36:46 with lambda expressions? Jun 21 19:36:49 JustinNShield, yes, various languages are amenable to this approach -- C# and Scala fall in between Haskell and Java for example Jun 21 19:36:54 I liked how the code bits weren't in pastebins, so that I could :r it into vim Jun 21 19:37:12 <__andrew__> it reminded me a lot of writing grammars - building up the different parts spaces, lower, upper and then gluing them together Jun 21 19:37:12 ivanm: With interfaces. :) Jun 21 19:37:21 Twey: *shudder* Jun 21 19:37:23 @where functionaljava Jun 21 19:37:23 http://functionaljava.org/ Jun 21 19:37:27 (f . g) x = f (g x) becomes some fifty lines of code Jun 21 19:37:28 Have to go also, but thanks for your time and work Tony. Had a ball and am sure will learn more again upon review. Cheers! Jun 21 19:37:30 you will find (.) in that library ^^ Jun 21 19:37:38 toddity, ok thanks, bye Jun 21 19:37:42 AdrianPronk, http://paste.pocoo.org/show/124288/ Jun 21 19:37:53 10:35:49 < ivanm> in FP, you usually do lots of little functions and glue them together Jun 21 19:37:55 Thanks Jun 21 19:38:12 Twey: hmmm? Jun 21 19:38:25 As for me, I tend to glue them together and then write lots of little functions, which I think makes it top-down Jun 21 19:38:31 ahhh Jun 21 19:38:43 Tony, do you have time now for a few newbie questions not related to this session? Jun 21 19:38:50 AdrianPronk, absolutely Jun 21 19:38:51 Twey: using foo = undefined or something? that's what dons et. al. recommend in RWH... Jun 21 19:38:56 Has the advantage that you start off by writing your ideal code, so you're not constrained by existing design Jun 21 19:38:59 ivanm: Yes Jun 21 19:39:29 koala_man, put this at the top of your source file: import Control.Applicative Jun 21 19:39:33 I normally plan out the "overall scope" in my head, start work on one little bit and write that, then conglomerate them together Jun 21 19:40:05 koala_man, and import Control.Monad Jun 21 19:40:07 Twey: OK, FP makes bottom-up programming a lot easier ;-) Jun 21 19:40:09 happy? :p Jun 21 19:40:14 I guess I also have a newbie question. For the character parsing, let say for instance that we wanted to ensure that the names were all in upper case. Is this where we would use a left fold and parse the string as a list of characters? Jun 21 19:40:19 ok Jun 21 19:40:36 JustinNShield, why not (list upper)? Jun 21 19:40:57 ivanm: Hehe Jun 21 19:41:10 I'm trying to understand the basics from 1st principles, so I made the following: myadd :: (Num a) => a -> a -> a Jun 21 19:41:10 myadd a b = a + b Jun 21 19:41:10 mydebug :: (Show a, Show b, Show c) => (a -> b -> c) -> a -> b -> ([String], c) Jun 21 19:41:10 mydebug f a b = let Jun 21 19:41:10 c = f a b Jun 21 19:41:12 s = "f(" ++ show a ++ ", " ++ show b ++ ") = " ++ show c Jun 21 19:41:14 I feel it also makes top-down programming a lot easier, too, though Jun 21 19:41:14 in ([s], c) Jun 21 19:41:14 TonyMorris: thank you, Tony - that was really good and clear :-) Jun 21 19:41:20 So that doesn't say much :-P Jun 21 19:41:41 Twey: I find if I do the low-level stuff first, I get a better idea of how to write the high-level stuff so it plays nicely with the lower-level ones Jun 21 19:42:15 Thanks everyone! Jun 21 19:42:29 TonyMorris: your IRC log has every line duplicated... your two nicks fighting or something? Jun 21 19:42:38 yes thank you - fun evening Jun 21 19:42:40 gah, yes -- I'll fix that Jun 21 19:42:48 AdrianPronk, what is your questions? Jun 21 19:42:49 I find if I do the high-level stuff first, I get a better idea of how to write the low-level stuff so it plays nicely with the higher-level ones... and itself :-P Jun 21 19:42:56 * MitchellRiley has quit (Remote closed the connection) Jun 21 19:43:14 The idea is that you get the ideal API first, then fill in the implementation, rather than letting implementation dictate what the API will look like Jun 21 19:43:20 * ivanm heads off as well now Jun 21 19:43:45 koala_man, http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6107#a6107 add this to the end of your source file Jun 21 19:43:49 * Twey will stick around fo a bit in case there are questions, but is only half-here Jun 21 19:43:54 * acidjnk (i=acid@pD9508E2E.dip0.t-ipconnect.de) has joined #bfpg Jun 21 19:43:59 hello Jun 21 19:44:04 hello Jun 21 19:44:12 acidjnk, we just finished, sorry Jun 21 19:44:22 Tony: So I do something like mydebug (+) 7 8 giving ("f(7, 8) = 15",15) Jun 21 19:44:44 :-( Jun 21 19:44:50 But you said it would start in 16 minutes Jun 21 19:45:10 I think I might have made a miscalculation, but you had disappeared -- I am very sorry Jun 21 19:45:12 This is following up on something I read about the background to Monads Jun 21 19:45:29 I will give you a personal session in return for my mistake Jun 21 19:45:42 AdrianPronk, I am following, but I cannot see how this relates to monads Jun 21 19:45:59 * __andrew__ has quit ("thanks a lot") Jun 21 19:46:00 weird Jun 21 19:46:13 koala_man, weird? Jun 21 19:46:26 yes Jun 21 19:47:05 I read some Haskell Tutorial article that talked about the idea of overloading a function to perform some secondary side effect, e.g. debugging Jun 21 19:47:08 * JustinNShield waves goodbye to Tony and the BFPG Jun 21 19:47:14 bye JustinNShield Jun 21 19:47:17 nvm, I already planned other things to do. Jun 21 19:47:19 Cheers guys, good session. Jun 21 19:47:22 bye Jun 21 19:47:38 * JustinNShield has quit () Jun 21 19:47:41 AdrianPronk, ah I think I know what you mean Jun 21 19:47:53 AdrianPronk, it relates specifically to performing a side-effect inside a function Jun 21 19:48:20 e.g. myadd :: a -> b -> c cannot print anything Jun 21 19:48:31 but myadd :: a -> b -> IO c can Jun 21 19:48:39 and IO is a monad Jun 21 19:48:53 notice that when we wrote "instance Monad Parser" Jun 21 19:48:59 we passed in "Parser" not "Parser a" Jun 21 19:49:06 this is not a full type Jun 21 19:49:24 it's a type constructor Jun 21 19:49:30 Parser takes a type argument to produce a type Jun 21 19:49:38 e.g. Parser Int <-- this is a type Jun 21 19:49:44 monads are type constructors Jun 21 19:49:52 e.g. Parser is a monad Jun 21 19:49:57 IO is also a monad Jun 21 19:50:10 @type print Jun 21 19:50:11 forall a. (Show a) => a -> IO () Jun 21 19:50:21 time to sign off for me too guys. thanks for your time (esp. Tony and Ivan). catch ya next time. Jun 21 19:50:27 you might write: print "boo" and you now have a value of type IO () Jun 21 19:50:32 bye OliverReeves Jun 21 19:50:39 Bye OJ Jun 21 19:50:46 see ya :) Jun 21 19:50:49 how do you get to IO c from IO () ? Jun 21 19:50:51 * OliverReeves (n=OJ@115.64.213.55) has left #bfpg ("Leaving") Jun 21 19:50:53 well using bind of course Jun 21 19:51:10 but you're not actually interested in the () value (the thing that print returned) Jun 21 19:51:15 so you can use anonymous-bind Jun 21 19:51:24 Haskell's real function for that is >> Jun 21 19:51:45 so you can write: print "boo" >> return (a + b) Jun 21 19:51:48 or Jun 21 19:51:56 do _ <- print "boo"; return (a + b) Jun 21 19:52:02 do print "boo"; return (a + b) Jun 21 19:52:16 I haven't really "internalised" what bind et al do so I'm trying to make up little examples Jun 21 19:52:29 Or do () <- print "boo"; return (a + b) Jun 21 19:53:10 Currently, I can't read those snippets and make a lot of sense of them Jun 21 19:53:50 http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6108#a6108 Jun 21 19:53:51 try that Jun 21 19:54:58 myaddIO3 :: Int -> Int -> IO Int Jun 21 19:54:58 myaddIO3 a b = forM_ [a, b] print >> return (a + b) Jun 21 19:55:30 notice that we can use (>>) on any monad Jun 21 19:55:49 this includes IO, but it also includes Parser, and all the others we might write or that exist in the standard library Jun 21 19:56:00 we have abstracted on the type constructor Jun 21 19:56:11 the type system requires *higher kinds* to achieve this Jun 21 19:56:15 So can I do (+) 1 $ myaddIO2 3 4 Jun 21 19:56:17 Haskell and Scala can achieve this Jun 21 19:56:25 almost! Jun 21 19:56:38 let's look at it closely Jun 21 19:56:43 myaddIO2 3 4 :: IO Int Jun 21 19:56:45 agree? Jun 21 19:56:52 y Jun 21 19:56:59 (+) 1 :: Int -> Int Jun 21 19:57:09 so you want: Jun 21 19:57:15 IO Int -> (Int -> Int) -> IO Int Jun 21 19:57:27 or more generally Jun 21 19:57:32 IO a -> (a -> b) -> IO b Jun 21 19:57:55 once you're in IO, you're in there for good -- this is a very strict rule of Haskell Jun 21 19:58:25 if you had a function :: IO a -> (a -> b) -> IO b Jun 21 19:58:34 then you could pass it myaddIO2 3 4 and (+) 1 Jun 21 19:58:36 therefore everything else you do must be able to deal with IO? Jun 21 19:58:44 that function is called liftM or fmap (they are both the same) Jun 21 19:59:18 it just means that if your function performs IO, or uses a function that performs IO, then the type of this function must denote this fact in its type Jun 21 19:59:33 you can "map" through a pure function -- but you'll end up in IO on the other side Jun 21 19:59:44 e.g. (+) 1 is a pure function Jun 21 19:59:55 but you're constructing a function which itself performs IO Jun 21 20:00:10 So, I presume that if you want to pass an IO result to a pure function you need to strip the IO somehow? Jun 21 20:00:19 no, you simply won't be able to Jun 21 20:00:30 you will have to use fmap or liftM Jun 21 20:00:47 fmap (+ 1) (myaddIO2 3 4) Jun 21 20:00:55 this will return you IO Int Jun 21 20:01:29 if you import Control.Applicative you can also use <$> (which almost resembles what you had) Jun 21 20:01:38 (+) 1 $ myaddIO2 3 4 Jun 21 20:01:41 becomes Jun 21 20:01:47 (+ 1) <$> myaddIO2 3 4 Jun 21 20:02:03 <$>, fmap, liftM are all the same Jun 21 20:02:22 importantly, if you're in IO, you're in there for good Jun 21 20:02:33 it is not possible for a function to perform IO without its signature denoting this fact Jun 21 20:02:40 Ok. I don't really have a good handle on this. I'll have to work through a few examples etc. Jun 21 20:02:50 conversely, you can look at a signature without IO and determine that it never performs IO Jun 21 20:03:01 AdrianPronk, this takes a *long* time to get used to in my experience Jun 21 20:03:09 AdrianPronk, but the advantages are immense Jun 21 20:03:16 AdrianPronk, did you attend JAOO 2008? Jun 21 20:03:36 No. What is JAOO Jun 21 20:03:43 if you did, you would have seen Erik Meijer jumping all over the place -- this is what he was jumping around about Jun 21 20:03:53 it is a conference -- the 2009 one was recently held Jun 21 20:04:18 Erik Meijer did the introductory keynote for 2008 Jun 21 20:04:30 and I think the whole audience had no idea what he was talking about Jun 21 20:04:45 but it can be summed up "our functions should not perform IO unless the type says so" Jun 21 20:05:08 the theme was "solving the software crisis" Jun 21 20:05:21 Erik proposes this solution (and I most adamantly agree with him) Jun 21 20:05:26 Was he talking about FP or Java? Jun 21 20:05:30 Haskell Jun 21 20:05:59 it was once a Java conference, but it morphed Jun 21 20:06:00 Ok, So the J of JAOO isn't Java then? I thought J wa sreserved for Java :) Jun 21 20:06:16 I think it used to stand for Java Jun 21 20:07:06 So far, BFPG and online tutorials are my only resource for learning Haskell. I'm finding some of the pattern syntax a bit hard going. Jun 21 20:07:16 there is a watered down version of this "effect system" proposed for Java in a JSR Jun 21 20:07:27 ok, well ask questions any time Jun 21 20:07:34 #haskell is just next door and they love helping Jun 21 20:07:48 Well, I was mucking around with State: Jun 21 20:08:03 State, the data type? Jun 21 20:08:03 myget :: State s s Jun 21 20:08:04 myget = State (\s -> (s, s)) Jun 21 20:08:04 myput :: s -> State s () Jun 21 20:08:04 myput x = State (const ( (), x) ) Jun 21 20:08:12 ok cool Jun 21 20:08:35 notice how Parser takes a type parameter to produce a type Jun 21 20:08:38 State takes two Jun 21 20:08:43 But I couldn't get this to compile: Jun 21 20:08:44 myapply :: (a -> a) -> State s a -> State s a Jun 21 20:08:45 myapply f s@(State x) = State (\s' -> let Jun 21 20:08:45 (a, s'') = runState s' Jun 21 20:08:45 a' = f $ evalState s Jun 21 20:08:45 in (a', s'')) Jun 21 20:08:51 monads must be type constructors that take one Jun 21 20:09:00 so you can apply one (State s) and this is a monad Jun 21 20:09:11 your let/in must line up Jun 21 20:09:53 Haskell gives you the choice of using {} and ; or you can adhere to whitespace rules Jun 21 20:10:43 Ok, I'll try and fix that. standby 5... Jun 21 20:13:38 > let myapply f s@(State x) = State (\s' -> let (a, s'') = runState s'; a' = f $ evalState s in (a', s'')) Jun 21 20:13:39 not an expression: `let myapply f s@(State x) = State (\s' -> let (a, s'') ... Jun 21 20:14:03 (a, s'') = runState s' Jun 21 20:14:03 a' = f $ evalState s Jun 21 20:14:03 in (a', s'')) Jun 21 20:14:36 does this work? Jun 21 20:14:47 t.hs:18:52: Jun 21 20:14:47 Couldn't match expected type `(t, t1)' Jun 21 20:14:47 against inferred type `s -> (a, s)' Jun 21 20:14:47 In the expression: runState s' Jun 21 20:14:47 In a pattern binding: (a, s'') = runState s' Jun 21 20:14:48 In the expression: Jun 21 20:14:50 let Jun 21 20:14:52 (a, s'') = runState s' Jun 21 20:14:54 a' = f $ evalState s Jun 21 20:14:56 in (a', s'') Jun 21 20:14:58 t.hs:19:41: Jun 21 20:15:00 Occurs check: cannot construct the infinite type: a = s -> a Jun 21 20:15:02 When generalising the type(s) for `a'' Jun 21 20:15:16 In the first argument of `State', namely Jun 21 20:15:18 `(\ s' Jun 21 20:15:20 -> let Jun 21 20:15:22 (a, s'') = runState s' Jun 21 20:15:24 a' = f $ evalState s Jun 21 20:15:26 in (a', s''))' Jun 21 20:15:28 Failed, modules loaded: none. Jun 21 20:15:32 The State constructor takes a lambda (is that right) and I don't know how to manipulate it Jun 21 20:15:39 do you have your source file? can you paste it to hpaste.org ? Jun 21 20:15:43 @src State Jun 21 20:15:44 Source not found. You untyped fool! Jun 21 20:15:52 data State s a = State (s -> (s, a)) Jun 21 20:17:31 http://hpaste.org/fastcgi/hpaste.fcgi/view?id=6109#a6109 Jun 21 20:18:40 are you trying to write map? Jun 21 20:18:45 myapply :: (a -> a) -> State s a -> State s a Jun 21 20:18:45 myapply = fmap Jun 21 20:21:55 myapply :: (a -> b) -> State s a -> State s b Jun 21 20:21:55 myapply f s = State(\t -> let (p, q) = runState s t in (f p, q)) Jun 21 20:21:56 ? Jun 21 20:22:14 Yes, I suppose so. Just trying to understand the basics by doing it. Jun 21 20:22:29 (notice that if you replace (State s) with Parser you have the signature to "mapParser") Jun 21 20:23:55 try this one Jun 21 20:24:11 mybind :: (a -> State s b) -> State s a -> State s b Jun 21 20:25:17 I was looking through the source code provided with WinHugs (ghci only has .hi files) and it didn't have runstate. Jun 21 20:25:40 http://www.haskell.org/ghc/docs/latest/html/libraries/mtl/Control-Monad-State.html Jun 21 20:25:47 there is a link in the top right "Source Code" Jun 21 20:25:59 which is not very helpful for this case Jun 21 20:26:01 It just has: newtype State s a = State { runState :: s -> (a, s) } Jun 21 20:26:23 http://www.haskell.org/ghc/docs/latest/html/libraries/mtl/src/Control-Monad-State-Lazy.html Jun 21 20:26:33 do you understand that syntax? Jun 21 20:27:10 I asked about that during the session. You said it was a field called runState with the given type signature. Jun 21 20:27:17 Is it also a cons? Jun 21 20:27:27 no Jun 21 20:27:31 :: and : are very different Jun 21 20:27:36 read :: as "is of the type" Jun 21 20:27:51 you're defining a type signature Jun 21 20:27:58 this is different to cons (prepend) to a list Jun 21 20:28:11 I meant cons == constructor Jun 21 20:28:42 ah right Jun 21 20:28:53 yes you can observe the type of runState Jun 21 20:29:13 it gives you access to the function for a given instance of State s a Jun 21 20:29:38 runState :: State s a -> s -> (a, s) Jun 21 20:29:46 if you have a value of type State s a Jun 21 20:29:48 call it s Jun 21 20:30:11 then you can write: runState s and then you will have a value of type s -> (a, s) Jun 21 20:32:05 Cale is good at explaining State -- he did the other day Jun 21 20:32:15 @seen Cale Jun 21 20:32:16 Cale is in #haskell, #haskell-overflow, #haskell-in-depth, #ghc and #bfpg. I last heard Cale speak 1h 48m 51s ago. Jun 21 20:33:10 I was reading his session with TheColonial the other day and found it pretty interesting. That was partially what I was basing my exercises on. Jun 21 20:33:27 ah right, cool Jun 21 20:33:36 I'm a little bit sleepy at the moment... but I might be able to answer some questions :) Jun 21 20:34:19 I think I'm just going to have to plough through a shed-load more exercises before the penny drops. But since I'm currently unemployed, I've got plenty of time :) Jun 21 20:35:24 Anyway Tony, I should wrap it up. Thanks for your help and for the session. You make it all seem so simple and I'll know I'll get there before too long. Jun 21 20:35:47 no problem, remember lots of questions Jun 21 20:36:33 First mission: get Internet working back at home. A service upgrade by my ISP has cut us off all weekend :(