From andrewcoppin at btinternet.com Sun Jul 1 05:18:16 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 05:12:12 2007 Subject: [Haskell-cafe] Abstraction leak In-Reply-To: <1405223741.20070630220456@gmail.com> References: <468551E0.20903@btinternet.com> <732225452.20070630110549@gmail.com> <46860AC3.9020306@btinternet.com> <1405223741.20070630220456@gmail.com> Message-ID: <46877158.4000200@btinternet.com> Bulat Ziganshin wrote: > Hello Andrew, > > Saturday, June 30, 2007, 11:48:19 AM, you wrote: > >> Well anyway, speed is not my aim. My aim is to play with various >> textbook algorithms an examine how well they work for various types of >> data. As long as the code isn't *absurdly* slow that'll be just fine. >> > > yes, for studying algorithms Haskell is perfect tool > > >> (I forget who it was, but a while back somebody pointed out the wisdom >> of using Data.Map. It certainly makes the LZW implementation about 400% >> faster! To say nothing of Huffman...) >> > > it seems that you've done first implementation with lists or immutable > arrays? :) > Lists. In fact, I *believe* the code is still on the Wiki somewhere... >> BTW, how do the pros do Huffman coding? Presumably not by traversing >> trees of pointer-linked nodes to process things 1 bit at a time... >> > > encoding is simple - make this traversal one time and store bit > sequence for each symbol. for decoding, you can find length of longest > symbol MaxBits and build table of 2^MaxBits elements which allows to > find next symbol by direct lookup with next input MaxBits. faster > algorithms use two-level lookup, first lookup with 9-10 bits is best > when your encoded symbols are bytes > I see. So build a table of codes and bitmasks and test against that... From andrewcoppin at btinternet.com Sun Jul 1 05:27:39 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 05:21:34 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: References: <468551E0.20903@btinternet.com> <20070629195537.GB26447@darcs.net> Message-ID: <4687738B.1040002@btinternet.com> apfelmus wrote: > Am I missing something or why wouldn't > > encode, decode :: String -> String > encode = encodeRLE . encodeHuffman > decode = decodeHuffman . decodeRLE > > do the job? This is probably what Andrew intends to do in his Java > version. Note that this not only RLE-encodes the Huffman table but also > (needlessly) the data stream. In case you only want to RLE the table, a > simple Word32 field tracking the size of the Huffman table should be enough. > It is enough. But given that the whole purpose of compression algorithms is to squeeze data into the tiniest possible space, I wanted to avoid having a size field. And mathematically it's perfectly possible to do... I just can't find a convinient way to do it in Haskell. :-( From apfelmus at quantentunnel.de Sun Jul 1 05:50:10 2007 From: apfelmus at quantentunnel.de (apfelmus) Date: Sun Jul 1 05:44:33 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: <4687738B.1040002@btinternet.com> References: <468551E0.20903@btinternet.com> <20070629195537.GB26447@darcs.net> <4687738B.1040002@btinternet.com> Message-ID: Andrew Coppin wrote: > apfelmus wrote: >> Am I missing something or why wouldn't >> >> encode, decode :: String -> String >> encode = encodeRLE . encodeHuffman >> decode = decodeHuffman . decodeRLE >> >> do the job? This is probably what Andrew intends to do in his Java >> version. Note that this not only RLE-encodes the Huffman table but also >> (needlessly) the data stream. In case you only want to RLE the table, a >> simple Word32 field tracking the size of the Huffman table should be >> enough. >> > > It is enough. But given that the whole purpose of compression algorithms > is to squeeze data into the tiniest possible space, I wanted to avoid > having a size field. And mathematically it's perfectly possible to do... > I just can't find a convinient way to do it in Haskell. :-( Well, those 4 bytes won't kill you. But you can of course stop RLE-decoding as soon as this has read as many bytes as there are in the Huffman table. A systematic way to do this are parser combinators. Regards, apfelmus From andrewcoppin at btinternet.com Sun Jul 1 06:04:04 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 05:58:00 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: References: <468551E0.20903@btinternet.com> <20070629195537.GB26447@darcs.net> <4687738B.1040002@btinternet.com> Message-ID: <46877C14.805@btinternet.com> apfelmus wrote: > Andrew Coppin wrote: > >> >> It is enough. But given that the whole purpose of compression algorithms >> is to squeeze data into the tiniest possible space, I wanted to avoid >> having a size field. And mathematically it's perfectly possible to do... >> I just can't find a convinient way to do it in Haskell. :-( >> > > Well, those 4 bytes won't kill you. But you can of course stop > RLE-decoding as soon as this has read as many bytes as there are in the > Huffman table. A systematic way to do this are parser combinators. > Yeah... I'm fuzzy on how to do this. I can write parsers to do the various stages, and I can run one parser on top of another. But how to you swap whole "stacks" of parsers when the top-most one reaches a given stage? From andrewcoppin at btinternet.com Sun Jul 1 08:33:31 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 08:27:26 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: <46877C14.805@btinternet.com> References: <468551E0.20903@btinternet.com> <20070629195537.GB26447@darcs.net> <4687738B.1040002@btinternet.com> <46877C14.805@btinternet.com> Message-ID: <46879F1B.8000708@btinternet.com> OK, well I don't know the Parsec types and function names off the top of my head, but suppose I have the following: runParser :: Parser a b -> [a] -> Either ParseError b parseHuffmanTable :: [x] -> Parser Word8 (HuffmanTable x) parseHuffmanPayload :: HuffmanTable x -> Parser Word8 [x] parseRLE :: Parser Word8 [Word8] Now, if I want to just do without the RLE bit, I can do parseHuffman :: [x] -> Parser Word8 x parseHuffman xs = do table <- parseHuffmanTable xs parseHuffmanPayload table But if I want to add an RLE layer to just the Huffman table... erm... OK, I'm stuck now. :-S 1. How do I run the input through parseRLE and *then* through parseHuffmanTable? 2. How do I get parseHuffmanPayload to continue from where parseRLE left off? (How do I get parseRLE to not parse the entire input, for that matter...) From apfelmus at quantentunnel.de Sun Jul 1 09:12:56 2007 From: apfelmus at quantentunnel.de (apfelmus) Date: Sun Jul 1 09:07:06 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: <46879F1B.8000708@btinternet.com> References: <468551E0.20903@btinternet.com> <20070629195537.GB26447@darcs.net> <4687738B.1040002@btinternet.com> <46877C14.805@btinternet.com> <46879F1B.8000708@btinternet.com> Message-ID: Andrew Coppin wrote: > OK, well I don't know the Parsec types and function names off the top of > my head, but suppose I have the following: > > runParser :: Parser a b -> [a] -> Either ParseError b > > parseHuffmanTable :: [x] -> Parser Word8 (HuffmanTable x) > > parseHuffmanPayload :: HuffmanTable x -> Parser Word8 [x] > > parseRLE :: Parser Word8 [Word8] > > Now, if I want to just do without the RLE bit, I can do > > parseHuffman :: [x] -> Parser Word8 x > parseHuffman xs = do > table <- parseHuffmanTable xs > parseHuffmanPayload table > > But if I want to add an RLE layer to just the Huffman table... erm... > OK, I'm stuck now. :-S > > 1. How do I run the input through parseRLE and *then* through > parseHuffmanTable? > > 2. How do I get parseHuffmanPayload to continue from where parseRLE left > off? (How do I get parseRLE to not parse the entire input, for that > matter...) Well, there's no way to do that with a monolithic parseRLE since it will parse the input to the bitter end. But assuming that parseRLE = concat `liftM` many parseRLEBlock parseRLEBlock :: Parser Word8 [Word8] you can write an RLE parser that repeatedly parses RLE blocks until it has read equal or more than n Word8s parseRLEAmount n | n <= 0 = return [] | otherwise = do xs <- parseRLEBlock xss <- parseRLEAmount (n - length xs) return (xs ++ xss) To parse a huffman table, run the actual parser on the result of parseRLEAmount: parseHuffmanHeader = runParser parseHuffmanTable `liftM` parseRLEAmount (2^8) Regards, apfelmus From claus.reinke at talk21.com Sun Jul 1 09:44:43 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Sun Jul 1 09:38:49 2007 Subject: [Haskell-cafe] Parsers are monadic? References: <977238.58691.qm@web31401.mail.mud.yahoo.com><004d01c7bb1b$08f5b520$43118351@cr3lt> <4E272D02-83FD-46E5-9C95-3DC823687EB6@math.columbia.edu> Message-ID: <006001c7bbe5$fc23d4a0$8d187ad5@cr3lt> > When you pretend you've never heard of monads or arrows, and > write down the types what do you get? this question made me wonder whether i could still recall how i used to write parsers before i heard of monads or arrows. it is difficult not to fall back into the pattern of state transformer monads, but -just for fun- here's an quick approximation of double-continuation-based parser combinators, where each parser takes a success and a failure continuation. the success continuation takes a parse result and the remaining text, the failure continuation takes the remaining text. the basic combinators are 'litP predicate' (parsing a literal/character), '.>' (sequence of two parsers), '.|' (alternative of two parsers), '.:' and '..:' (process and combine parse results before passing them to the success continuation). '?>' ignores its first result, '#>' pairs its two results (i'm sure i didn't use as many cute combinators at the time:-). [ to those of you writing debuggers for haskell: this kind of functional programming -programming with functions- could be a good stress test for your tool ] claus ------------------------------------------------ import Data.Char infixr .>,.|,?>,#> type Parser a t = (a->String->t) -> (String->t) -> (String->t) empty s f = \cs-> s () cs eot s f = \cs-> case cs of { "" -> s '\EOT' ""; '\EOT':_ -> s '\EOT' ""; _ -> f cs } litP p s f = \cs-> case cs of { c:cs' | p c -> s c cs'; _ -> f cs } but x s f = \cs-> x (\_ _->f cs) (\_->s undefined cs) cs (a ?> b) s f = \cs->a (\ar->b s (\_->f cs)) f cs (a #> b) s f = \cs->a (\ar->b (s . ((,)ar)) (\_->f cs)) f cs (a .> b) s f = \cs->a (\ar->b (s ar) (\_->f cs)) f cs (a .| b) s f = a s (b s f) (parse .: build) s f = parse (s . build) f (parse ..: build) s f = parse ((s .) . build) f parse p = ((p .> eot) ..: const) (const . Right) Left many p = (( p .> many p ) ..: (:) ) .| ( p .: return ) digit = litP isDigit .: digitToInt digits = many digit num = digits .: (foldl ((+) . (10*)) 0) space = litP isSpace anyChar = litP (const True) nonSpace = ( but space ?> anyChar ) sep = litP (==':') field = ( many nonSpace #> many space ?> sep ?> many space ?> many nonSpace ) nonField = but field ?> many anyChar From andrewcoppin at btinternet.com Sun Jul 1 09:52:24 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 09:46:18 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: References: <468551E0.20903@btinternet.com> <20070629195537.GB26447@darcs.net> <4687738B.1040002@btinternet.com> <46877C14.805@btinternet.com> <46879F1B.8000708@btinternet.com> Message-ID: <4687B198.8020601@btinternet.com> apfelmus wrote: > Andrew Coppin wrote: > >> OK, I'm stuck now. :-S >> >> 1. How do I run the input through parseRLE and *then* through >> parseHuffmanTable? >> >> 2. How do I get parseHuffmanPayload to continue from where parseRLE left >> off? (How do I get parseRLE to not parse the entire input, for that >> matter...) >> > > Well, there's no way to do that with a monolithic parseRLE since it will > parse the input to the bitter end. But assuming that > > parseRLE = concat `liftM` many parseRLEBlock > > parseRLEBlock :: Parser Word8 [Word8] > > you can write an RLE parser that repeatedly parses RLE blocks until it > has read equal or more than n Word8s > > parseRLEAmount n > | n <= 0 = return [] > | otherwise = do > xs <- parseRLEBlock > xss <- parseRLEAmount (n - length xs) > return (xs ++ xss) > > To parse a huffman table, run the actual parser on the result of > parseRLEAmount: > > parseHuffmanHeader = > runParser parseHuffmanTable `liftM` parseRLEAmount (2^8) > The use of lifeM is *inspired* - I would never have thought of writing it infix! Still, while this does solve the issue at hand, I'm still left wondering whether there's any way to make this work for some arbitrary parser. parseHuffmanTable always uses exactly N bytes of input, but what if it didn't? What if it was impossible to tell how many bytes it should read without actually running it? How would you implement that? Nice a since general solution exist? From bulat.ziganshin at gmail.com Sun Jul 1 10:04:56 2007 From: bulat.ziganshin at gmail.com (Bulat Ziganshin) Date: Sun Jul 1 10:00:24 2007 Subject: [Haskell-cafe] sha1 implementation thats "only" 12 times slower then C In-Reply-To: References: Message-ID: <693140511.20070701180456@gmail.com> Hello Anatoly, Sunday, July 1, 2007, 3:58:24 AM, you wrote: > Anyone have any pointers on how to get hashElem and updateElem to run > faster, or any insight on what exactly they are allocating. To me it > seems that those functions should be able to do everything they need > to without a malloc. haskell allocations isn't a malloc, it's just a pointer increment, so it's very fast. any temporary data created in haskell code need to be allocated so the only case when you don't have allocations is cycle on unboxed values in your particular case you should try the following trick: aa <- unsafeRead a5 0 return $! aa bb <- unsafeRead a5 1 return $! bb currently, your code implies that unsafeRead may return boxed value. 'let' by itself doesn't enforce unboxing, the compiler implies that value assigned in 'let' may be actually not used. you can use either 'case' or above-mentioned trick with '$!' (or seq) to avoid boxing -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com From bulat.ziganshin at gmail.com Sun Jul 1 10:18:59 2007 From: bulat.ziganshin at gmail.com (Bulat Ziganshin) Date: Sun Jul 1 10:16:53 2007 Subject: [Haskell-cafe] Abstraction leak In-Reply-To: <46877158.4000200@btinternet.com> References: <468551E0.20903@btinternet.com> <732225452.20070630110549@gmail.com> <46860AC3.9020306@btinternet.com> <1405223741.20070630220456@gmail.com> <46877158.4000200@btinternet.com> Message-ID: <384417510.20070701181859@gmail.com> Hello Andrew, Sunday, July 1, 2007, 1:18:16 PM, you wrote: >> encoding is simple - make this traversal one time and store bit >> sequence for each symbol. for decoding, you can find length of longest >> symbol MaxBits and build table of 2^MaxBits elements which allows to >> find next symbol by direct lookup with next input MaxBits. faster >> algorithms use two-level lookup, first lookup with 9-10 bits is best >> when your encoded symbols are bytes >> > I see. So build a table of codes and bitmasks and test against that... decodeSymbol = do n <- returnNextNBits MaxBits -- this operation doesn't forward input pointer! symbol <- table1 ! n bits <- table2 ! symbol skipNBits bits return symbol -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com From andrewcoppin at btinternet.com Sun Jul 1 10:48:29 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 10:42:24 2007 Subject: [Haskell-cafe] Abstraction leak In-Reply-To: <384417510.20070701181859@gmail.com> References: <468551E0.20903@btinternet.com> <732225452.20070630110549@gmail.com> <46860AC3.9020306@btinternet.com> <1405223741.20070630220456@gmail.com> <46877158.4000200@btinternet.com> <384417510.20070701181859@gmail.com> Message-ID: <4687BEBD.9070904@btinternet.com> Bulat Ziganshin wrote: > Hello Andrew, > > >> I see. So build a table of codes and bitmasks and test against that... >> > > decodeSymbol = do > n <- returnNextNBits MaxBits -- this operation doesn't forward input pointer! > symbol <- table1 ! n > bits <- table2 ! symbol > skipNBits bits > return symbol > I see. While we're on the subject... am I the first person to notice that Haskell doesn't appear to have much support for fiddling with streams of bits? From paul.hudak at yale.edu Sun Jul 1 11:39:20 2007 From: paul.hudak at yale.edu (Paul Hudak) Date: Sun Jul 1 11:33:25 2007 Subject: [Haskell-cafe] Parsers are monadic? In-Reply-To: <004d01c7bb1b$08f5b520$43118351@cr3lt> References: <977238.58691.qm@web31401.mail.mud.yahoo.com> <004d01c7bb1b$08f5b520$43118351@cr3lt> Message-ID: <4687CAA8.2040601@yale.edu> Hi Claus. I am sympathetic with your comments regarding monads and continuations. It's interesting to note that the original I/O system in Haskell was based on streams and continuations. The continuation version had two continuations in fact -- one for success and one for failure. For example, readFile had the type: readFile :: Name -> FailCont -> StrCont -> Behaviour Here StrCont was the success continuation, which took a string (the file contents) as argument. I rather liked the flexibility that this offered -- since I/O errors were fairly common, it made sense to give success and failure equal status. The down-side of using continuations is that you have to carry them around explicitly, so one might argue that they clutter the code a bit, and that was one of the advantages of switching to monads. On the other hand, one could argue that having them explicit makes things in some way clearer. All of this is described in fair detail in the History of Haskell paper, by the way (see http://portal.acm.org/toc.cfm?id=1238844). It's worth noting that, in comparing continuation and monadic program fragments, we comment in that paper: Although these two code fragments have a somewhat imperative feel because of the way they are laid out, it was really the advent of do-notation?not monads themselves?that made Haskell programs look more like conventional imperative programs (for better or worse). This syntax seriously blurred the line between purely functional programs and imperative programs, yet was heartily adopted by the Haskell Committee. In retrospect it is worth asking whether this same (or similar) syntactic device could have been used to make stream or continuation-based I/O look more natural. Best wishes, -Paul Claus Reinke wrote: >> The standard, na?ve approach to monadic parsing is very nice, but >> inefficient. So *please read* some material based on Hutton&Meijer >> approach, but don't stay there, read something more modern, > > since we thereby seem to have left the phase of simple answers to > simple questions;-) i'd like to raise a pet issue of mine. my own first > combinator parsers (inspired by Wadler's "How to replace failure > by a list of successes", but adapted to a call-by-value language) > were based on continuations. > > .. > > ok, now everybody has had time to chime in with "monadic parsers > are based on continuations" or "continuations are just one specific > monad". so let me return to the particular issue i'm interested in: > contrary to monadic parsers, those continuation-based parsers > had *two* continuations, one for success, one for failure. and > that seemed to be a very natural match for the problem. > > for all that i like monadic programming in general, i often feel > that it is biased towards handling only the success path well, > by offering built-in support for a single continuation only. for > instance, one can use (Either String) as a parser monad with > error messages, but it isn't straightforward to express error > handling into that format, preserving both success and failure- > related info (such as reporting the error corresponding to the > longest partially successful parse). also, negation does not > seem to be an easy fit (succeed if a specific parser would > not be successful at the current point; this seems to require > monad-specific information, so perhaps there's a > MonadNegate class missing?). > > has anyone else had similar experiences with expressive limitations > of monadic programming? things that one might be able to work > around, but that don't feel as natural or simple as they should be? > things that one hasn't been able to express at all (such as Swierstra > & Duponcheel's static analysis of combinator parsers which > inspired Hughes's proposal to use arrows)? > > claus From andrewcoppin at btinternet.com Sun Jul 1 12:06:10 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 12:00:04 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: <20070629184753.GA3217@localhost.localdomain> References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> Message-ID: <4687D0F2.3030509@btinternet.com> Stefan O'Rear wrote: > This is *much* easier expressed as a bottom-up traversal. > > compile = transform optimize . transform eliminate > > eliminate (Lam v e) = transform (abstract v) e > eliminate x = x > > abstract v (Var v') | v == v' = I > abstract v (a :@ b) = S :@ a :@ b > abstract v x = x > > optimize (S :@ (K :@ x) :@ (K :@ y)) = K :@ (x :@ y) > optimize (S :@ (K :@ x) :@ I) = x > optimize x = x > > (Here using Uniplate, mostly because it is the freshest in my mind of > all of them). > Um... shouldn't that read abstract v (a :@ b) = S :@ (transform (abstract v) a) :@: (transform (abstract v) b) ? Or am I missing something? From stefanor at cox.net Sun Jul 1 12:09:32 2007 From: stefanor at cox.net (Stefan O'Rear) Date: Sun Jul 1 12:03:34 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: <4687D0F2.3030509@btinternet.com> References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> <4687D0F2.3030509@btinternet.com> Message-ID: <20070701160932.GA3391@localhost.localdomain> On Sun, Jul 01, 2007 at 05:06:10PM +0100, Andrew Coppin wrote: > Stefan O'Rear wrote: > >This is *much* easier expressed as a bottom-up traversal. > > > >compile = transform optimize . transform eliminate > > > >eliminate (Lam v e) = transform (abstract v) e > >eliminate x = x > > > >abstract v (Var v') | v == v' = I > >abstract v (a :@ b) = S :@ a :@ b > >abstract v x = x > > > >optimize (S :@ (K :@ x) :@ (K :@ y)) = K :@ (x :@ y) > >optimize (S :@ (K :@ x) :@ I) = x > >optimize x = x > > > >(Here using Uniplate, mostly because it is the freshest in my mind of > >all of them). > > > > Um... shouldn't that read > > abstract v (a :@ b) = S :@ (transform (abstract v) a) :@: (transform > (abstract v) b) No, because the whole point of transform is that it handles recursion for you. (However, there is a bug! abstracting an unrecognized form (that is, a primitive combinator) should add a K.) Stefan From jon.fairbairn at cl.cam.ac.uk Sun Jul 1 12:21:01 2007 From: jon.fairbairn at cl.cam.ac.uk (Jon Fairbairn) Date: Sun Jul 1 12:15:15 2007 Subject: [Haskell-cafe] Re: Abstraction leak References: <468551E0.20903@btinternet.com> <732225452.20070630110549@gmail.com> <46860AC3.9020306@btinternet.com> <1405223741.20070630220456@gmail.com> <46877158.4000200@btinternet.com> <384417510.20070701181859@gmail.com> <4687BEBD.9070904@btinternet.com> Message-ID: Andrew Coppin writes: > While we're on the subject... am I the first person to > notice that Haskell doesn't appear to have much support for > fiddling with streams of bits? No. Presumably the author of Data.Bits noticed some lack. (Note that Integer is an instance of Num and hence Bits) -- J?n Fairbairn Jon.Fairbairn@cl.cam.ac.uk From hughperkins at gmail.com Sun Jul 1 12:43:51 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 12:37:53 2007 Subject: [Haskell-cafe] sha1 implementation thats "only" 12 times slower then C In-Reply-To: <693140511.20070701180456@gmail.com> References: <693140511.20070701180456@gmail.com> Message-ID: <837db430707010943o2b950b22n575d7dfab4a033f9@mail.gmail.com> Just an outsider's reaction, and for all I know unsafeRead is actually safe, but.... if the point of using Haskell (and I'm still trying to discover what that is ;-) ) is either to be able to rigorously mathematically prove that your program will work perfectly (target usage 1), or to carry out threading easily and automatically (what I'm interested specifically in), ... then why do we have to throw unsafe functions around the place to get any decent speed??? Ok, I'll go back to my hole; just a reaction. I know everything has to start somewhere, and build up, just be aware that having to use unsafe stuff to get decent speed is not good PR ;-) -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070701/ecb4f158/attachment.htm From josef.svenningsson at gmail.com Sun Jul 1 12:51:48 2007 From: josef.svenningsson at gmail.com (Josef Svenningsson) Date: Sun Jul 1 12:45:49 2007 Subject: [Haskell-cafe] Abstraction leak In-Reply-To: <200706291707.55684.jcast@ou.edu> References: <468551E0.20903@btinternet.com> <200706291528.20122.jcast@ou.edu> <200706291707.55684.jcast@ou.edu> Message-ID: <8dde104f0707010951k96e5ccch5ab6b59db4010c53@mail.gmail.com> On 6/30/07, Jon Cast wrote: > On Friday 29 June 2007, Jon Cast wrote: > > Here's my solution (drawn from a library I'll be posting Real Soon Now): > > > I forgot to point out that this is 75-90% drawn from a library called > Fudgets[1], which is probably the most extended practical meditation to date > on programming with lazy streams in Haskell. Embedding that approach in a > monadic interface seems to be my own idea, though. > Koen Claessen had the same idea. He used it for designing parsers. See: http://www.cs.chalmers.se/~koen/pubs/entry-jfp04-parser.html > Jonathan Cast > http://sourceforge.net/projects/fid-core > http://sourceforge.net/projects/fid-emacs > > [1] http://www.md.chalmers.se/Cs/Research/Functional/Fudgets/ Cheers, Josef From hughperkins at gmail.com Sun Jul 1 12:56:05 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 12:50:08 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <20070626213820.GB2072@web.de> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> Message-ID: <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> On 6/26/07, Udo Stenzel wrote: > > That's another way of saying that the truly powerful features are > missing from C#... > Hi Udo, Genuine question: please could you tell me what are the truly powerful features of Haskell? My own personal interest comes from a presentation by Tim Sweenie (Unreal 3 Engine), where he discusses some of the ways that Haskell may help solve the threading issues that currently are the Big Problem in computing right now. A friend of mine told me that they're also useful for mission-critical implementations where you want to mathematically prove that the program wont crash etc. Unfortunately it seems Haskell isnt totally perfect for mission-critical applications because (a) it is hard to predict memory usage (b) it's not real-time (eg garbage-collector might kick in just when it would be an appropriate time to fire those booster rockets.... ?) I'm basically a C# developer looking around for ways to solve threading. I'm interested in a few things: - solutions that might work in C# - solutions that could be integrated into C# later on - solutions that work in other languages Haskell looks like it could possibly "solve" threading at some point in the near future, or at least make a dent into threading issues. Given that Simon Peyton Jones is (a) heavily involved in the birth and development of Haskell (b) works at Microsoft Research, there's a decent chance that anything he gets working will be integrated into C# in the future. As far as C# integration goes, I'd guess some way of marking classes/methods "Pure", and having the compiler enforce this. Remember that the average programmer does not have a phd, or even a degree, so anything that requires formal mathematical training will *not* be adopted by a mainstream programming language, but most of the maths can probably be abstracted away. Anyway, getting back to my question, there's a whole slew of articles around saying that no-one uses Haskell because they're too stupid. That's certainly an argument, but it possibly lacks a certain objectivity ;-) So... what do you see as the "Killer Advantages" that make Haskell stand out from the pack? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070701/6d0e61e1/attachment.htm From andrewcoppin at btinternet.com Sun Jul 1 13:07:13 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 13:01:06 2007 Subject: [Haskell-cafe] Re: Abstraction leak In-Reply-To: References: <468551E0.20903@btinternet.com> <732225452.20070630110549@gmail.com> <46860AC3.9020306@btinternet.com> <1405223741.20070630220456@gmail.com> <46877158.4000200@btinternet.com> <384417510.20070701181859@gmail.com> <4687BEBD.9070904@btinternet.com> Message-ID: <4687DF41.4060403@btinternet.com> Jon Fairbairn wrote: > Andrew Coppin writes: > > >> While we're on the subject... am I the first person to >> notice that Haskell doesn't appear to have much support for >> fiddling with streams of bits? >> > > No. Presumably the author of Data.Bits noticed some > lack. (Note that Integer is an instance of Num and hence > Bits) > Right. But (for instance) there is no library function anywhere to convert a Word16 into a [Bool] (never mind handling endian issues), or back again. There is no standard construct for reading from a [Word8] as if it's a [Bool], or for writing to a [Bool] and ending up with a [Word8]... ...Then again, there is no library function for reading from a file and getting a [Word8]. The only way I have found to do this is to open a file, put the handle into "binary mode", use hGetContents to read a [Char] from it, and then do a map (fromIntegral . fromEnum) on that. Writing binary data back to a file requires opening a handle, putting it into binary mode, taking your [Word8] and doing a map (toEnum . fromIntegral) over it, and then using putStr. All of which works because, apparently, in binary mode the file is interpreted as 8-bit ASCII. God forbit that Haskell ever decides to transparently support other encodings... I haven't actually tried, but presumably a TCP connection is represented in the same way as a file, and so has the same problems. Basically doing binary I/O seems to be one of those things that in Haskell falls into the class of "it's possibly but annoyingly messy"... From andrewcoppin at btinternet.com Sun Jul 1 13:09:38 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 13:03:32 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: <20070701160932.GA3391@localhost.localdomain> References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> <4687D0F2.3030509@btinternet.com> <20070701160932.GA3391@localhost.localdomain> Message-ID: <4687DFD2.80502@btinternet.com> Stefan O'Rear wrote: > On Sun, Jul 01, 2007 at 05:06:10PM +0100, Andrew Coppin wrote: > >> Um... shouldn't that read >> abstract v (a :@ b) = S :@ (transform (abstract v) a) :@: (transform >> (abstract v) b) >> > > No, because the whole point of transform is that it handles recursion > for you. OK. Well in that case, I have no idea what transform is doing... (I assumed it was just applying some function to every part of the structure - but that wouldn't solve this case.) > (However, there is a bug! abstracting an unrecognized form > (that is, a primitive combinator) should add a K.) > I'm going to have to take some time to bend my mind around that one too... (Does anybody else on this list frequently get the feeling their IQ is just too low for Haskell??) From benja.fallenstein at gmail.com Sun Jul 1 13:12:29 2007 From: benja.fallenstein at gmail.com (Benja Fallenstein) Date: Sun Jul 1 13:06:31 2007 Subject: [Haskell-cafe] sha1 implementation thats "only" 12 times slower then C In-Reply-To: <693140511.20070701180456@gmail.com> References: <693140511.20070701180456@gmail.com> Message-ID: Hi, 2007/7/1, Bulat Ziganshin : > aa <- unsafeRead a5 0 > return $! aa > bb <- unsafeRead a5 1 > return $! bb If this is a useful pattern, would it make sense to have a function to encapsulate it? mseq :: Monad m => m a -> m a mseq m = m >>= (return $!) - Benja From andrewcoppin at btinternet.com Sun Jul 1 13:26:18 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 13:20:12 2007 Subject: [Haskell-cafe] TT check Message-ID: <4687E3BA.2080001@btinternet.com> Can somebody check that I've implemented this correctly? *****X*X*X*XX***X*X*XXX*X*X*XX***X*X*X*XX**X*X*XX**X*X*X*XX ***X*X*XXX*X*X*XX**XX*X*XX***X*X*XXX*X*XX****X*X*X*XX****X* X*X*XX***X*X*XXX*X*X*XXX*X*XXXX****X*X*XXX****X*X*X*XX***X* X*XXX*X*X*XXX*X*XXXX A parser for this is given by decode (c:cs) = case c of 'X' -> X '*' -> let (e0,cs0) = decode cs; (e1,cs1) = decode cs0 in (e0 `apply` e1, cs1) The letter X stands for the following combinator: X = \x -> xSK K = \xy -> x S = \fgx -> fx(gx) Assuming my Haskell code is correct, the above *should* be a program to compute the sum of the Church numberal 2 and the Church numeral 2. In other words, this is the world's most verbose way to define the act of putting two and two together. ;-) But... I don't know... that's A LOT of expression there! Have a slipped up somewhere? Does anybody have a way to check? From mark at ixod.org Sun Jul 1 13:47:36 2007 From: mark at ixod.org (Mark T.B. Carroll) Date: Sun Jul 1 13:41:42 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: <4687DFD2.80502@btinternet.com> (Andrew Coppin's message of "Sun, 01 Jul 2007 18:09:38 +0100") References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> <4687D0F2.3030509@btinternet.com> <20070701160932.GA3391@localhost.localdomain> <4687DFD2.80502@btinternet.com> Message-ID: <87ved4yq13.fsf@ixod.org> Andrew Coppin writes: (snip) > (Does anybody else on this list frequently get the feeling their IQ is > just too low for Haskell??) I do. But then, when I finally understand something, it seems easy and simple and I'm not sure why it wasn't obvious all along. -- Mark From felipe.lessa at gmail.com Sun Jul 1 13:48:25 2007 From: felipe.lessa at gmail.com (Felipe Almeida Lessa) Date: Sun Jul 1 13:42:26 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: <4687DFD2.80502@btinternet.com> References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> <4687D0F2.3030509@btinternet.com> <20070701160932.GA3391@localhost.localdomain> <4687DFD2.80502@btinternet.com> Message-ID: On 7/1/07, Andrew Coppin wrote: > (Does anybody else on this list frequently get the feeling their IQ is > just too low for Haskell??) That's the best part of learning Haskell. You're always in touch with the very best people --- directly or indirectly (i.e. using their libraries and documentation). -- Felipe. From aeyakovenko at gmail.com Sun Jul 1 14:07:42 2007 From: aeyakovenko at gmail.com (Anatoly Yakovenko) Date: Sun Jul 1 14:01:43 2007 Subject: [Haskell-cafe] sha1 implementation thats "only" 12 times slower then C In-Reply-To: References: <693140511.20070701180456@gmail.com> Message-ID: so using mseq didn't seem to make any difference, i still had the same performance. On 7/1/07, Benja Fallenstein wrote: > Hi, > > 2007/7/1, Bulat Ziganshin : > > aa <- unsafeRead a5 0 > > return $! aa > > bb <- unsafeRead a5 1 > > return $! bb > > If this is a useful pattern, would it make sense to have a function to > encapsulate it? > > mseq :: Monad m => m a -> m a > mseq m = m >>= (return $!) > > - Benja > From isaacdupree at charter.net Sun Jul 1 14:16:33 2007 From: isaacdupree at charter.net (Isaac Dupree) Date: Sun Jul 1 14:08:50 2007 Subject: [Haskell-cafe] TT check In-Reply-To: <4687E3BA.2080001@btinternet.com> References: <4687E3BA.2080001@btinternet.com> Message-ID: <4687EF81.7050602@charter.net> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Andrew Coppin wrote: > decode (c:cs) = case c of > 'X' -> X > '*' -> let (e0,cs0) = decode cs; (e1,cs1) = decode cs0 in (e0 `apply` > e1, cs1) > > The letter X stands for the following combinator: > > X = \x -> xSK > K = \xy -> x > S = \fgx -> fx(gx) > > Assuming my Haskell code is correct, ... Does anybody have a way > to check? Whether X is a data constructor or a function \x -> x S K, it isn't the same type as the tuple that the other case alternative returns, so you have a type error. If you had working haskell code, you could check if it worked by trying running the haskell code! (ghci/hugs can be convenient, if nothing else) Isaac -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGh++BHgcxvIWYTTURAg+QAKCYOZuV3/TwC4Ye8kMbSVy7D+UOJwCfadGG IJmQx8GfrXOiIADwO8np8og= =hfNa -----END PGP SIGNATURE----- From andrewcoppin at btinternet.com Sun Jul 1 15:06:27 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 15:00:21 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: <87ved4yq13.fsf@ixod.org> References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> <4687D0F2.3030509@btinternet.com> <20070701160932.GA3391@localhost.localdomain> <4687DFD2.80502@btinternet.com> <87ved4yq13.fsf@ixod.org> Message-ID: <4687FB33.3000909@btinternet.com> Mark T.B. Carroll wrote: > Andrew Coppin writes: > (snip) > >> (Does anybody else on this list frequently get the feeling their IQ is >> just too low for Haskell??) >> > > I do. But then, when I finally understand something, it seems easy and > simple and I'm not sure why it wasn't obvious all along. > *cough* monads *cough* ;-) From andrewcoppin at btinternet.com Sun Jul 1 15:07:02 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 15:00:56 2007 Subject: [Haskell-cafe] Language semantics In-Reply-To: References: <4682CCB1.1000604@btinternet.com> <20070627205418.GA4188@localhost.localdomain> <4682D665.2030802@btinternet.com> <200706271644.37061.jcast@ou.edu> <59ba068d0706271949n4b03964bk1731af7ae2ab6f8c@mail.gmail.com> <46854CD8.1090205@btinternet.com> <20070629184753.GA3217@localhost.localdomain> <4687D0F2.3030509@btinternet.com> <20070701160932.GA3391@localhost.localdomain> <4687DFD2.80502@btinternet.com> Message-ID: <4687FB56.1020701@btinternet.com> Felipe Almeida Lessa wrote: > On 7/1/07, Andrew Coppin wrote: >> (Does anybody else on this list frequently get the feeling their IQ is >> just too low for Haskell??) > > That's the best part of learning Haskell. You're always in touch with > the very best people --- directly or indirectly (i.e. using their > libraries and documentation). > I know what you mean... (Personally, I am still in awe of people who write Haskell programs that are *thousands* of lines long. I mean, like, wow!) From miguelimo38 at yandex.ru Sun Jul 1 15:07:09 2007 From: miguelimo38 at yandex.ru (Miguel Mitrofanov) Date: Sun Jul 1 15:04:47 2007 Subject: [Haskell-cafe] TT check In-Reply-To: <4687E3BA.2080001@btinternet.com> References: <4687E3BA.2080001@btinternet.com> Message-ID: <1342094706.20070701230709@yandex.ru> Hi Andrew! Seems that you've made a typo or something... > module Term where > import Control.Monad.State > testData = "*****X*X*X*XX**X*X*XX*X*X*X*XX*X*X*XX***X*X*X*XX" ++ > "***X*X*X*XX**X*X*XX*X*X*X*XX*X*X*XX*XX***X*X*X*X" ++ > "X***X*X*X*XX**X*X*XX*X*X*X*XX*X*X*XX*XX" > data Term = IntTerm Int | Term (Term -> Term) > inc = Term $ \x -> case x of IntTerm n -> IntTerm (n+1) > out x = case x of IntTerm n -> n > outCh x = out $ x `apply` inc `apply` IntTerm 0 > apply x y = case x of Term f -> f y > infixl `apply` > xComb = Term $ \x -> x `apply` sComb `apply` kComb > kComb = Term $ \x -> Term $ \y -> x > sComb = Term $ \f -> Term $ \g -> Term $ \x -> f `apply` x `apply` (g `apply` x) > decode = evalState decodeS where > decodeS = do c:cs <- get > put cs > case c of 'X' -> return xComb > '*' -> do f <- decodeS > x <- decodeS > return $ f `apply` x Then outCh $ decode testData prints "4", as desired, while your version simply fails. AC> Can somebody check that I've implemented this correctly? AC> *****X*X*X*XX***X*X*XXX*X*X*XX***X*X*X*XX**X*X*XX**X*X*X*XX AC> ***X*X*XXX*X*X*XX**XX*X*XX***X*X*XXX*X*XX****X*X*X*XX****X* AC> X*X*XX***X*X*XXX*X*X*XXX*X*XXXX****X*X*XXX****X*X*X*XX***X* AC> X*XXX*X*X*XXX*X*XXXX AC> A parser for this is given by AC> decode (c:cs) = case c of AC> 'X' -> X AC> '*' -> let (e0,cs0) = decode cs; (e1,cs1) = decode cs0 in (e0 AC> `apply` e1, cs1) AC> The letter X stands for the following combinator: AC> X = \x -> xSK AC> K = \xy -> x AC> S = \fgx -> fx(gx) From andrewcoppin at btinternet.com Sun Jul 1 15:16:11 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Sun Jul 1 15:10:04 2007 Subject: [Haskell-cafe] TT check In-Reply-To: <4687E3BA.2080001@btinternet.com> References: <4687E3BA.2080001@btinternet.com> Message-ID: <4687FD7B.2040405@btinternet.com> Wait a sec... I found a way. Sort of. http://ling.ucsd.edu/~barker/Iota/ From jcast at ou.edu Sun Jul 1 15:36:14 2007 From: jcast at ou.edu (Jon Cast) Date: Sun Jul 1 15:30:20 2007 Subject: [Haskell-cafe] Parsers are monadic? In-Reply-To: <004d01c7bb1b$08f5b520$43118351@cr3lt> References: <977238.58691.qm@web31401.mail.mud.yahoo.com> <004d01c7bb1b$08f5b520$43118351@cr3lt> Message-ID: <200707011436.16267.jcast@ou.edu> On Saturday 30 June 2007, Claus Reinke wrote: > >The standard, na?ve approach to monadic parsing is very nice, but > >inefficient. So *please read* some material based on Hutton&Meijer > >approach, but don't stay there, read something more modern, > > since we thereby seem to have left the phase of simple answers to > simple questions;-) i'd like to raise a pet issue of mine. my own first > combinator parsers (inspired by Wadler's "How to replace failure > by a list of successes", but adapted to a call-by-value language) > were based on continuations. > > .. > > ok, now everybody has had time to chime in with "monadic parsers > are based on continuations" or "continuations are just one specific > monad". so let me return to the particular issue i'm interested in: > contrary to monadic parsers, those continuation-based parsers > had *two* continuations, one for success, one for failure. and > that seemed to be a very natural match for the problem. Two-continuations is a monad too, right? newtype ContErrorT m alpha = ContErrorT { runContErrorT :: forall beta. (alpha -> m beta) -> (Exception -> m beta) -> m beta } instance Monad m => ContErrorT m where return x = ContErrorT (\ k h -> k x) a >>= f = ContErrorT (\ k h -> runContErrorT a (\ x -> runContErrorT (f x) k h) h) instance Monad m => MonadError Exception (ContError m) where throwError e = ContErroT ( \ k h -> h e) a `catchError` f = ContErrorT (\ k h -> runContErrorT a k (\ e -> runContErrorT (f e) k h)) Am I missing something really obvious here? Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs From hughperkins at gmail.com Sun Jul 1 16:31:04 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 16:25:08 2007 Subject: [Haskell-cafe] Parsers are monadic? In-Reply-To: References: <977238.58691.qm@web31401.mail.mud.yahoo.com> Message-ID: <837db430707011331u73450f7bm69d24bd9d4d2cd93@mail.gmail.com> Big Chris wrote: > http://www.cs.nott.ac.uk/~gmh/bib.html#monparsing Hey, just to say, the first few pages of this explain monads really well. Good reference :-) It's the first introduction to monads I've seen that describes monads directly, without using analogies, and manages to be both sufficiently simple and precise as to be understandable. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070701/ece6316c/attachment-0001.htm From bulat.ziganshin at gmail.com Sun Jul 1 16:37:19 2007 From: bulat.ziganshin at gmail.com (Bulat Ziganshin) Date: Sun Jul 1 16:37:34 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> Message-ID: <1707588565.20070702003719@gmail.com> Hello Hugh, Sunday, July 1, 2007, 8:56:05 PM, you wrote: > Genuine question: please could you tell me what are the truly powerful features of Haskell? > Anyway, getting back to my question, there's a whole slew of > articles around saying that no-one uses Haskell because they're too > stupid.? That's certainly an argument, but it possibly lacks a certain objectivity ;-) i agree with it. haskell represents new programming paradigm and most programmers are unable to learn it without help of college in other words, there is not yet enough learning infrastructure for FP languages. the same situation was in 80s for OOP languages. this means that learning FP require much more work, or, spending the same time, one will learn FP much worse than OOP > So... what do you see as the "Killer Advantages" that make Haskell stand out from the pack? i've written 8kloc "real world" program in haskell and can say what was killer features for me: - natural data structures and easiness of defining algorithms - rich set of list operations - easiness of use of higher-level functions - type inference (dropping almost all declarations) - strong type checking detects many errors just at compile time - non-updateable data simplifies algorithms development for concurrent programming: - it's easy to split algorithm to several parts that are run concurrently and exchange data - channels allows to organize data streams (like Unix pipes) between threads, non-updatability of data significantly simplifies usage of these data - MVar allows to implement shared updateable variables which automatically locks on their use shortly said, non-updatability of data significantly simplifies both usual programming and concurrency, especially later. you can do the same with C# it's an example how i use concurrency for data archiving and compression: - first thread scans disk and finds files to compress. it sends filenames to its output stream - second thread reads contents of these files and sends memory buffers filled with data read to its output stream. it also runs background decompression stream which decompress data from old archive - third thread runs one or several C streams which compress its input buffers and sends buffers with compressed data to output stream. it may be several threads that do it, making a pipe - fourth thread writes compressed data to output archive all four threads are started by line runP$ scanning |> reading |> compression |> writing where each thread represented by a function which has additional argument for exchanging data with previous and next thread in list: reading pipe = do nextFile <- readP pipe .... writeP pipe buffer running additional background thread and exchanging information with it is also trivial: decompressor <- runAsyncP decompressor writeP decompressor request buffer <- readP decompressor you can see module which implements this as Process.hs from http://www.haskell.org/bz/FreeArc-sources.tar.gz although it's actually only a thin layer around forkIO/Chan/MVar features you can do the same in C# although i guess that syntax overhead will be a bit more and allocating a lot of small non-updateable values may be less efficient because its GC isn't aimed to such usage btw, are you read Hoar's book "Communicating Sequential Processes"? i think that his model is very FPish and reading his book should allow to switch your look at concurrency in right direction -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com From hughperkins at gmail.com Sun Jul 1 16:48:11 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 16:42:12 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <1707588565.20070702003719@gmail.com> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> <1707588565.20070702003719@gmail.com> Message-ID: <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> Ok good info :-) > btw, are you read Hoar's book "Communicating Sequential Processes"? i think that his model is very FPish and reading his book should allow to switch your look at concurrency in right direction No, I'll check it out. On 7/1/07, Bulat Ziganshin wrote: > > Hello Hugh, > > Sunday, July 1, 2007, 8:56:05 PM, you wrote: > > > Genuine question: please could you tell me what are the truly powerful > features of Haskell? > > > Anyway, getting back to my question, there's a whole slew of > > articles around saying that no-one uses Haskell because they're too > > stupid. That's certainly an argument, but it possibly lacks a certain > objectivity ;-) > > i agree with it. haskell represents new programming paradigm and most > programmers are unable to learn it without help of college > > in other words, there is not yet enough learning infrastructure for FP > languages. the same situation was in 80s for OOP languages. this means > that learning FP require much more work, or, spending the same time, > one will learn FP much worse than OOP > > > So... what do you see as the "Killer Advantages" that make Haskell stand > out from the pack? > > i've written 8kloc "real world" program in haskell and can say what > was killer features for me: > > - natural data structures and easiness of defining algorithms > - rich set of list operations > - easiness of use of higher-level functions > - type inference (dropping almost all declarations) > - strong type checking detects many errors just at compile time > - non-updateable data simplifies algorithms development > > for concurrent programming: > - it's easy to split algorithm to several parts that are run > concurrently and exchange data > - channels allows to organize data streams (like Unix pipes) between > threads, non-updatability of data significantly simplifies usage of > these data > - MVar allows to implement shared updateable variables which > automatically locks on their use > > shortly said, non-updatability of data significantly simplifies > both usual programming and concurrency, especially later. you can do > the same with C# > > it's an example how i use concurrency for data archiving and > compression: > - first thread scans disk and finds files to compress. it sends > filenames to its output stream > - second thread reads contents of these files and sends memory buffers > filled with data read to its output stream. it also runs background > decompression stream which decompress data from old archive > - third thread runs one or several C streams which compress its input > buffers and sends buffers with compressed data to output stream. it > may be several threads that do it, making a pipe > - fourth thread writes compressed data to output archive > > all four threads are started by line > > runP$ scanning |> reading |> compression |> writing > > where each thread represented by a function which has additional > argument for exchanging data with previous and next thread in list: > > reading pipe = do > nextFile <- readP pipe > .... > writeP pipe buffer > > running additional background thread and exchanging information with > it is also trivial: > > decompressor <- runAsyncP decompressor > writeP decompressor request > buffer <- readP decompressor > > you can see module which implements this as Process.hs from > http://www.haskell.org/bz/FreeArc-sources.tar.gz although it's > actually only a thin layer around forkIO/Chan/MVar features > > you can do the same in C# although i guess that syntax overhead will > be a bit more and allocating a lot of small non-updateable values may > be less efficient because its GC isn't aimed to such usage > > btw, are you read Hoar's book "Communicating Sequential Processes"? i > think that his model is very FPish and reading his book should allow > to switch your look at concurrency in right direction > > > -- > Best regards, > Bulat mailto:Bulat.Ziganshin@gmail.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070701/fec73306/attachment.htm From hughperkins at gmail.com Sun Jul 1 17:58:47 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 17:52:48 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> <1707588565.20070702003719@gmail.com> <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> Message-ID: <837db430707011458t4f288d55w3c5065ec70f20c92@mail.gmail.com> Well, figured out a solution to parsing xml. It's not really pretty, but it works. Basically we just convert the incoming xml into a gread compatible format then use gread :-D If someone has a more elegant solution, please let me know. module ParseXml where import IO import Char import List import Maybe import Data.Generics hiding (Unit) import Text.XML.HXT.Arrow hiding (when) data Config = Config{ name :: String, age :: Int } --data Config = Config{ age :: Int } deriving( Data, Show, Typeable, Ord, Eq, Read ) createConfig = Config "qsdfqsdf" 3 --createConfig = Config 3 gshow' :: Data a => a -> String gshow' t = fromMaybe (showConstr(toConstr t)) (cast t) -- helper function from http://www.defmacro.org/ramblings/haskell-web.html introspectData :: Data a => a -> [(String, String)] introspectData a = zip fields (gmapQ gshow' a) where fields = constrFields $ toConstr a -- function to create xml string from single-layer Haskell data type xmlSerialize object = "<" ++ show(toConstr object) ++ ">" ++ foldr (\(a,b) x -> x ++ "<" ++ a ++ ">" ++ b ++ "") "" ( introspectData object ) ++ "" -- parse xml to HXT tree, and obtain the value of node "fieldname" -- returns a string getValue xml fieldname | length(resultlist) > 0 = Just (head resultlist) | otherwise = Nothing where resultlist = (runLA ( constA xml >>> xread >>> deep ( hasName fieldname ) >>> getChildren >>> getText ))[] -- parse templateobject to get list of field names -- apply these to xml to get list of values -- return (fieldnames list, value list) xmlToGShowFormat :: Data a => String -> a -> String xmlToGShowFormat xml templateobject = go where mainconstructorname = (showConstr $ toConstr templateobject) fields = constrFields $ toConstr templateobject values = map ( \fieldname -> getValue xml fieldname ) fields datatypes = gmapQ (dataTypeOf) templateobject constrs = gmapQ (toConstr) templateobject datatypereps = gmapQ (dataTypeRep . dataTypeOf) templateobject fieldtogshowformat (value,datatyperep) = case datatyperep of IntRep -> "(" ++ fromJust value ++ ")" _ -> show(fromJust value) formattedfieldlist = map (fieldtogshowformat) (zip values datatypereps) go = "(" ++ mainconstructorname ++ " " ++ (concat $ intersperse " " formattedfieldlist ) ++ ")" xmlDeserialize xml templateobject = fst $ head $ gread( xmlToGShowFormat xml templateobject) dotest = xmlDeserialize (xmlSerialize createConfig) createConfig :: Config dotest' = xmlDeserialize ("12test name!") createConfig :: Config -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070701/d23c28d9/attachment.htm From phil at kantaka.co.uk Sun Jul 1 18:19:04 2007 From: phil at kantaka.co.uk (Philip Armstrong) Date: Sun Jul 1 18:13:04 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> <1707588565.20070702003719@gmail.com> <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> Message-ID: <20070701221904.GA14585@kantaka.co.uk> On Sun, Jul 01, 2007 at 10:48:11PM +0200, Hugh Perkins wrote: > On 7/1/07, Bulat Ziganshin <[1]bulat.ziganshin@gmail.com> wrote: > > btw, are you read Hoar's book "Communicating Sequential Processes"? i > > think that his model is very FPish and reading his book should allow > > to switch your look at concurrency in right direction > No, I'll check it out. Just as a point of interest, Jim Davies at Oxford University Computing Lab. has edited a revised edition of Tony Hoare's book which is freely available from . (Full disclosure: my day job is/was developing CSP-related tools.) Phil -- http://www.kantaka.co.uk/ .oOo. public key: http://www.kantaka.co.uk/gpg.txt From hughperkins at gmail.com Sun Jul 1 18:23:36 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Sun Jul 1 18:17:36 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <20070701221904.GA14585@kantaka.co.uk> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> <1707588565.20070702003719@gmail.com> <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> <20070701221904.GA14585@kantaka.co.uk> Message-ID: <837db430707011523m6fe254b4k76b048a23a7e9fb6@mail.gmail.com> Coooolll :-) Thanks for the link. Ermmmm.... are you the Philip Armstrong I was at college with???? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070702/5b678060/attachment.htm From dry.green.tea at gmail.com Sun Jul 1 21:07:32 2007 From: dry.green.tea at gmail.com (Alexis Hazell) Date: Sun Jul 1 21:01:41 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? In-Reply-To: <400018.6689.qm@web31406.mail.mud.yahoo.com> References: <400018.6689.qm@web31406.mail.mud.yahoo.com> Message-ID: <200707021107.33918.dry.green.tea@gmail.com> On Sunday 01 July 2007 09:34, Gregory Propf wrote: > Thanks, that was helpful. I didn't realize that there were pure functional > monads. Neither did i; the general impression i'd got after almost a year of trying to learn Haskell was: "Monad Eisley Spaceport. You will never find a more wretched hive of sequencing and impurity. We must be cautious." :-) Alexis. From jules at jellybean.co.uk Mon Jul 2 04:40:09 2007 From: jules at jellybean.co.uk (Jules Bean) Date: Mon Jul 2 04:34:04 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? In-Reply-To: <400018.6689.qm@web31406.mail.mud.yahoo.com> References: <400018.6689.qm@web31406.mail.mud.yahoo.com> Message-ID: <4688B9E9.6080906@jellybean.co.uk> Gregory Propf wrote: > Thanks, that was helpful. I didn't realize that there were pure > functional monads. Actually, it's stronger than that. All monads are pure functional, even IO. Haskell is an entirely 100% pure functional language[*]. The IO monad allows you to build up, in a pure, referentially transparent way, an object call an 'IO action' which you have no way of actually executing, per se. Fortunately, this isn't as useless as it sounds since the runtime system contains the support to "actually run" the special IO action called 'main', which bootstraps the whole setup. Jules [*] non-functions like unsafePerformIO are not technically part of the haskell language! From apfelmus at quantentunnel.de Mon Jul 2 07:01:55 2007 From: apfelmus at quantentunnel.de (apfelmus) Date: Mon Jul 2 06:56:14 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? In-Reply-To: <4687CAA8.2040601@yale.edu> References: <977238.58691.qm@web31401.mail.mud.yahoo.com> <004d01c7bb1b$08f5b520$43118351@cr3lt> <4687CAA8.2040601@yale.edu> Message-ID: Paul Hudak wrote: > > readFile :: Name -> FailCont -> StrCont -> Behaviour > > Here StrCont was the success continuation, which took a string (the file > contents) as argument. I rather liked the flexibility that this offered > -- since I/O errors were fairly common, it made sense to give success > and failure equal status. > Claus Reinke wrote: >> contrary to monadic parsers, those continuation-based parsers >> had *two* continuations, one for success, one for failure. and >> that seemed to be a very natural match for the problem. In a sense, the MonadError class class Monad m => MonadError e m | m -> e where throwError :: e -> m a catchError :: m a -> (e -> m a) -> m a defines a second monad structure, with return = throwError bind = catchError To make this apparent and symmetric, let's define a class DiMonad m where returnR :: a -> m e a bindR :: m e a -> (a -> m e b) -> m e b returnL :: e -> m e a bindL :: m e a -> (e -> m e' a) -> m e' a A dimonad m e a can be thought of as a monad m e with a variable error type e . The operations with suffixed by R are the "normal" monad operations whereas the suffix L marks the "error"-catching operations. (Question: can dimonads solve the extensible-exceptions problem?) Now, the two-continuation approach always requires to pass two continuations. But here, returnL and returnR only pass the failure- or the success-continuation. To see what's happening, let's turn type TwoCont e a = (e -> R) -> (a -> R) -> R with some fixed result type R into a dimonad (for clarity, we ignore that this is only a type-synonym): instance DiMonad TwoCont where returnR x = \e a -> a x bindR m f = \e a -> m e (\x -> (f x) e a) returnL y = \e a -> e y bindL m f = \e a -> m (\y -> (f y) e a) a In the case of success-continuation, this means that the dimonad passes one and the same error continuation, i.e. one and the same exception-handler will the thrown regardless of where the failure happens inside a chain of actions composed with bindR. Likewise, error-handler and success-chain will be resumed at with a common success-chain. Of course, this is well-known behavior for IO and exceptions, and it seems that it reduces clutter quite well compared to a bare TwoCont. A final question remains: does the dimonad abstraction cover the full power of TwoCont? I mean, it still seems like there's an operation missing that supplies new left and right continuations at once. Regards, apfelmus From claus.reinke at talk21.com Mon Jul 2 07:16:33 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Mon Jul 2 07:10:38 2007 Subject: [Haskell-cafe] Parsers are monadic? References: <977238.58691.qm@web31401.mail.mud.yahoo.com><004d01c7bb1b$08f5b520$43118351@cr3lt> <200707011436.16267.jcast@ou.edu> Message-ID: <009c01c7bc9a$73cfeb60$8c318351@cr3lt> >> contrary to monadic parsers, those continuation-based parsers >> had *two* continuations, one for success, one for failure. and >> that seemed to be a very natural match for the problem. > >Two-continuations is a monad too, right? yes, but my problem is not about giving them a monadic interface, but about getting more advantages than disadvantages out of that. the initial definitions are more complicated than using continuations directly, and usually, the monadic interface forces me to interleave handling of the two paths into a single thread of specifications. and while instances of the monadic combinators can be defined to thread information for both continuations, i still have to inject that information outside the monadic interface, and make sure that it doesn't get reset to nothing just because someone calls Monad fail (via a library function or pattern-match failure), or MonadPlus mzero (via things like guard). a second problem is that some of the advantages of monadic interfaces that i tend to rely on heavily, such as pattern-match failure handling in do-notation, are hardwired to the wrong part of the monadic interface (Monad fail). this is not something a non-monadic approach would offer any help with, though.. > instance Monad m => Monad (ContErrorT m) where .. > instance Monad m => MonadError Exception (ContErrorT m) where .. > > Am I missing something really obvious here? interesting. i tend to use Monad/MonadPlus for sequence/ alternative, rather than Monad/MonadError, but you're right: MonadError's method types are a more natural dual to Monad's. they don't have to be limited to Exception, either. it seems i should be using that class more. actually, i am using that class, via the ErrorT transformer, but i guess i thought of MonadError only as error handling in sequences (which is the way it is usually presented) rather than as fallthrough in alternatives. it would force me to decide in advance whether i want fallthrough branches (MonadError) or collections of alternatives (MonadPlus), whereas MonadPlus allowed me to delay that decision (using MonadPlus Maybe for fallthrough or MonadPlus [] for collections, for instance). hmm, perhaps one can abstract over that decision. now, if we could replace calls to Monad fail (especially, pattern match failure in do-notation) with calls to MonadError throwError, we might actually be getting somewhere (similarly, we'd need to replace MonadPlus-based guard with a MonadError-based variant). as a start, fail msg = throwError (PatternMatchError msg) isn't too far off, but it would be lying for fail called from library functions, not to mention that it would still be limited to Strings. but i've already used my own variant of catchError to limit information loss and preserve the most specific error message, so once again, MonadError seems a natural fit. all in all, your answer only strengthens my view that monadic programming would be more symmetric if we always had two continuations, one for failure, one for success. then do-notation translation could rely on both Monad and MonadError, using throwError instead of fail (it has been suggested to use mzero, with a separate MonadZero class, but MonadError may well be the better match). perhaps there'll come a time when the monadic aspects of haskell will need redesign, similar to the numeric aspects. thanks! this emphasized view of MonadError might help. claus From hthiel.char at zonnet.nl Mon Jul 2 08:14:12 2007 From: hthiel.char at zonnet.nl (Hans van Thiel) Date: Mon Jul 2 07:58:54 2007 Subject: [Haskell-cafe] Re: Tree Guidance In-Reply-To: References: <1182863040.28031.23.camel@localhost.localdomain> <46812E07.9050003@list.mightyreason.com> <46813049.30104@list.mightyreason.com> <1182962460.6541.15.camel@localhost.localdomain> Message-ID: <1183378452.3188.1.camel@localhost.localdomain> On Fri, 2007-06-29 at 19:35 +0200, Thomas Schilling wrote: > On 27 jun 2007, at 18.41, Hans van Thiel wrote: > > > [snip] > > > > Thanks, Apfelmus, for the references. Guess I'll start there, then. > > And > > thanks, Chris, for the info and code. Read only 'up pointers' could be > > what is needed. But before going on, I want first to get more > > confortable with programming with trees. It's all very well to say > > they're easy to roll, but lists are even simpler, and look at them... > > I guess it's in the papers, too, but the chapter on zippers in the > Wikibook is very nice, too: > > http://en.wikibooks.org/wiki/Haskell/Zippers > > / Thomas Yes, I've seen this. Thanks! Regards, Hans From phil at kantaka.co.uk Mon Jul 2 08:25:45 2007 From: phil at kantaka.co.uk (Philip Armstrong) Date: Mon Jul 2 08:19:44 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <837db430707011523m6fe254b4k76b048a23a7e9fb6@mail.gmail.com> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> <1707588565.20070702003719@gmail.com> <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> <20070701221904.GA14585@kantaka.co.uk> <837db430707011523m6fe254b4k76b048a23a7e9fb6@mail.gmail.com> Message-ID: <20070702122545.GB8969@kantaka.co.uk> On Mon, Jul 02, 2007 at 12:23:36AM +0200, Hugh Perkins wrote: > Coooolll :-) Thanks for the link. > > Ermmmm.... are you the Philip Armstrong I was at college with???? Shhh. Don't tell everyone or they'll all want one. (iow, yes: Probably.) Phil -- http://www.kantaka.co.uk/ .oOo. public key: http://www.kantaka.co.uk/gpg.txt From claus.reinke at talk21.com Mon Jul 2 09:54:43 2007 From: claus.reinke at talk21.com (Claus Reinke) Date: Mon Jul 2 09:48:46 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? References: <977238.58691.qm@web31401.mail.mud.yahoo.com> <004d01c7bb1b$08f5b520$43118351@cr3lt><4687CAA8.2040601@yale.edu> Message-ID: <00c901c7bcb0$8c274bc0$8c318351@cr3lt> > class Monad m => MonadError e m | m -> e where > throwError :: e -> m a > catchError :: m a -> (e -> m a) -> m a >.. > power of TwoCont? I mean, it still seems like there's an operation > missing that supplies new left and right continuations at once. i guess, instead of one DiMonad with two sets of operations, i'd prefer to have two separate Monads with the ability to connect them, so that failure in one is success in the other, but i guess we need some way to tell which is which. using MonadError to handle error continuations on top of a Monad to handle success continuation is a lot like using a MonadReader to hold error continuations on top of the base Monad. consider class (Monad m) => MonadReader r m | m -> r where ask :: m r local :: (r -> r) -> m a -> m a where r = e -> m a. then throwError = \e->ask >>= \h->h e catchError m h = local (const h) m in other words, supplying both continuations is straightforward, although syntactic sugar only supports supplying one, in line with the bias towards one of the two continuations: m `doubleBind` (s,f) = m `catchError` f >>= s i find myself doing something like this frequently, whenever i use constructs like m >>= \x-> a x `mplus` b x m >>= maybe a b m >>= either a b btw, it might be useful if throwing an error would reverse the roles of the two continuations, instead of throwing away the success continuation. then the error handler itself could either return (abandoning the original success continuation) or throw (resuming the original continuation). that would interfere with the use of throw to pass on unhandled errors, but then we could be more specific about which direction to throw. claus From apfelmus at quantentunnel.de Mon Jul 2 10:31:34 2007 From: apfelmus at quantentunnel.de (apfelmus) Date: Mon Jul 2 10:25:55 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? In-Reply-To: References: <977238.58691.qm@web31401.mail.mud.yahoo.com> <004d01c7bb1b$08f5b520$43118351@cr3lt> <4687CAA8.2040601@yale.edu> Message-ID: apfelmus wrote: > class DiMonad m where > returnR :: a -> m e a > bindR :: m e a -> (a -> m e b) -> m e b > > returnL :: e -> m e a > bindL :: m e a -> (e -> m e' a) -> m e' a > > type TwoCont e a = (e -> R) -> (a -> R) -> R > > A final question remains: does the dimonad abstraction cover the full > power of TwoCont? I mean, it still seems like there's an operation > missing that supplies new left and right continuations at once. I think that this missing operation is bind2 :: m e a -> (e -> m e' a') -> (a -> m e' a') -> m e' a' It executes the second or the third argument depending on whether the first argument is a failure or a success. First, bind2 can be defined for TwoCont bind2 m fe fa = \e' a' -> m (\e -> (fe e) e' a') (\a -> (fa a) e' a') Apparently, bindL and bindR can be expressed with bind2 bindL m f = bind2 m f returnR bindR m f = bind2 m returnL f The question is whether bind2 can be expressed by bindL and bindR or whether bind2 offers more than both. It turns out that bind2 can be formulated from bindL and bindR alone fmapR f m = m `bindR` returnR . f bind2 m fe fa = ((Left `fmapR` m) `bindL` (\e -> Right `fmapR` fe e)) `bindR` (\aa' -> case aa' of Left a -> fa a Right a' -> returnR a') The definitions is rather cumbersome and we omit the proof that both definitions for bind2 are the same for TwoConts. For a general proof, we'd need an axiomatic characterization of dimonads and bind2. Recast in the light of MonadError, bind2 gives rise to a combinator bind2 :: MonadError e m => m a -> (e -> m b) -> (a -> m b) -> m b that executes either failure or success path. The important point is the inequality bind2 m fe fa ? (m >>= fa) `catchError` fe There's no equivalent to bind2 (with a better name, of course) in the libraries at the moment. The only function that does come near bind2 in the libraries is Control.Exception.try :: IO a -> IO (Either Exception a) which can be used rather easily to implement bind2 of course. Interestingly, the existence of try shows that there is a natural isomorphism DiMonad m => m e a ? m () (Either e a) so that dimonads do not add anything beyond what monads can already do. (More precisely, try gives one direction. The other direction is rather obvious.) Regards, apfelmus From jcast at ou.edu Mon Jul 2 11:01:23 2007 From: jcast at ou.edu (Jonathan Cast) Date: Mon Jul 2 10:55:40 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? In-Reply-To: References: <977238.58691.qm@web31401.mail.mud.yahoo.com> Message-ID: <200707021001.24925.jcast@ou.edu> On Monday 02 July 2007, apfelmus wrote: > apfelmus wrote: > > class DiMonad m where > > returnR :: a -> m e a > > bindR :: m e a -> (a -> m e b) -> m e b > > > > returnL :: e -> m e a > > bindL :: m e a -> (e -> m e' a) -> m e' a > > > > type TwoCont e a = (e -> R) -> (a -> R) -> R > > > > A final question remains: does the dimonad abstraction cover the full > > power of TwoCont? I mean, it still seems like there's an operation > > missing that supplies new left and right continuations at once. > > I think that this missing operation is > > bind2 :: m e a -> (e -> m e' a') -> (a -> m e' a') -> m e' a' > > It executes the second or the third argument depending on whether the > first argument is a failure or a success. > > First, bind2 can be defined for TwoCont > > bind2 m fe fa = \e' a' -> m (\e -> (fe e) e' a') (\a -> (fa a) e' a') > > Apparently, bindL and bindR can be expressed with bind2 > > bindL m f = bind2 m f returnR > bindR m f = bind2 m returnL f > > The question is whether bind2 can be expressed by bindL and bindR or > whether bind2 offers more than both. It turns out that bind2 can be > formulated from bindL and bindR alone > > fmapR f m = m `bindR` returnR . f > bind2 m fe fa = > ((Left `fmapR` m) `bindL` (\e -> Right `fmapR` fe e)) > `bindR` > (\aa' -> case aa' of > Left a -> fa a > Right a' -> returnR a') Exactly. > The definitions is rather cumbersome As you point out below, try makes it easier: try a = liftM Right a `catchE` return . Left bind2 m fe fa = try a >>= either fe fa And, of course, it's not cheating, since try and either are both independently useful in their own rights. And if you want to eliminate try, it's still a one-liner: bind2 m fe fa = (liftM Right a `catchE` return . Left) >>= either fe fa is still a one-line (71 characters), and bind2 m fe fa = join (liftM fa a `catchE` return . fe) is even shorter. (Proof: by a >>= f = join (liftM f a) and natural transformations). > and we omit the proof that both definitions for bind2 are the same for > TwoConts. try a >>= either fe fa = \ ke ka -> try a ke (\ x -> either fe fa x ke ka)) = \ ke ka -> (\ ke' ka' -> a (ka' . Left) (ka' . Right)) ke (\ x -> either fe fa x ke ka) = \ ke ka -> a ((\ x -> either fe fa x ke ka) . Left) ((\ x -> either fe fa x ke ka) . Right) = \ ke ka -> a (\ x -> fe x ke ka) (\ x -> fa x ke ka) Not hard. > For a general proof, > we'd need an axiomatic characterization of dimonads and bind2. Harder :) But I think the definition of bind2 above is good enough. (Is it easier to define MonadError axiomatically in terms of throw/try than throw/catch? catch a h = try a >>= either h return ) Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs From jim at sdf-eu.org Mon Jul 2 11:10:33 2007 From: jim at sdf-eu.org (Jim Burton) Date: Mon Jul 2 11:04:31 2007 Subject: [Haskell-cafe] N00b question In-Reply-To: <11389624.post@talk.nabble.com> References: <11389624.post@talk.nabble.com> Message-ID: <11395620.post@talk.nabble.com> poop wrote: > > So I'm working my way thorough haskell, doing some programming problems, > and I have this one so far: > Hi, I haven't spotted the problem in your code but there's an alternative solution to Euler Problem 14 on the wiki: http://www.haskell.org/haskellwiki/Euler_problems/11_to_20#Problem_14 -- it may be helpful as a comparison? Regards, > p14next n = if (mod n 2 == 0) then (div n 2) else (3*n + 1) > > p14seqlen n = f' 1 n where > f' accum n > | n == 1 = accum > | otherwise = f' (accum + 1) (p14next n) > > sndmax a b = if snd a > snd b then a else b > > p14 n = fst (f' (0,0) n) where > f' maxTuple n > | n == 0 = maxTuple > | otherwise = f' (sndmax maxTuple (n, p14seqlen n)) (n-1) > > the goal is to be able to run: > p14 999999 > > and not get a stack overflow message. I read what was available on tail > recursion and I think I have it working with tail recursion now, at least > it gives me a stack overflow message really quickly compared to before :) > > I have not been able to find any documentation on seq and ($!) which was > also mentioned as a way to get rid of stack overflow messages so if those > are what is required an explanation of those would be most helpful. > > -- View this message in context: http://www.nabble.com/N00b-question-tf4010616.html#a11395620 Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com. From andrewcoppin at btinternet.com Mon Jul 2 13:35:09 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Mon Jul 2 13:28:59 2007 Subject: [Haskell-cafe] Before Message-ID: <4689374D.3050909@btinternet.com> What were monads like before they became a Haskell language construct? Is Haskell's idea of a "monad" actually anywhere close to the original mathematical formalism? Just being randomly curiose... From hughperkins at gmail.com Mon Jul 2 14:06:42 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Mon Jul 2 14:00:40 2007 Subject: [Haskell-cafe] XmlSerializer.deserialize? In-Reply-To: <20070702122545.GB8969@kantaka.co.uk> References: <837db430706240514h544ed681u526e85bb3cf2bf59@mail.gmail.com> <20070624234103.GA2072@web.de> <837db430706261226x33a7f19cj29919bb57d6d71bf@mail.gmail.com> <20070626213820.GB2072@web.de> <837db430707010956l6793e2aek2aafb90f5b726aed@mail.gmail.com> <1707588565.20070702003719@gmail.com> <837db430707011348o75b0d573ibc25c528f739a0c1@mail.gmail.com> <20070701221904.GA14585@kantaka.co.uk> <837db430707011523m6fe254b4k76b048a23a7e9fb6@mail.gmail.com> <20070702122545.GB8969@kantaka.co.uk> Message-ID: <837db430707021106o3ccb5ff0r8c4973c094579767@mail.gmail.com> lol small world :-) On 7/2/07, Philip Armstrong wrote: > > On Mon, Jul 02, 2007 at 12:23:36AM +0200, Hugh Perkins wrote: > > Coooolll :-) Thanks for the link. > > > > Ermmmm.... are you the Philip Armstrong I was at college with???? > > Shhh. Don't tell everyone or they'll all want one. (iow, yes: Probably.) > > Phil > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070702/ff53dd85/attachment.htm From dpiponi at gmail.com Mon Jul 2 14:21:12 2007 From: dpiponi at gmail.com (Dan Piponi) Date: Mon Jul 2 14:15:10 2007 Subject: [Haskell-cafe] Before In-Reply-To: <4689374D.3050909@btinternet.com> References: <4689374D.3050909@btinternet.com> Message-ID: <625b74080707021121n4218b50bk5fb620dba7d7b0a@mail.gmail.com> On 7/2/07, Andrew Coppin wrote: > What were monads like before they became a Haskell language construct? > > Is Haskell's idea of a "monad" actually anywhere close to the original > mathematical formalism? It's as close to a mathematician's notion of a monad as Haskell's types and functions are to the objects and arrows of category theory. They are essentially the same thing. Using the notation here: http://en.wikipedia.org/wiki/Monad_%28category_theory%29 'return' is eta and join is mu. If you're more familiar with >>= than join, then its definition is > join x = x >>= id and I'll leave recovering >>= from join as a nice exercise. Knowing that you were about to ask this question I told my past self by tachyon express and wrote up on it this weekend: http://sigfpe.blogspot.com/2007/06/monads-from-algebra-and-the-gray-code.html -- Dan From andrewcoppin at btinternet.com Mon Jul 2 14:33:13 2007 From: andrewcoppin at btinternet.com (Andrew Coppin) Date: Mon Jul 2 14:27:02 2007 Subject: [Haskell-cafe] Before In-Reply-To: <625b74080707021121n4218b50bk5fb620dba7d7b0a@mail.gmail.com> References: <4689374D.3050909@btinternet.com> <625b74080707021121n4218b50bk5fb620dba7d7b0a@mail.gmail.com> Message-ID: <468944E9.4070205@btinternet.com> Dan Piponi wrote: > On 7/2/07, Andrew Coppin wrote: >> What were monads like before they became a Haskell language construct? >> >> Is Haskell's idea of a "monad" actually anywhere close to the original >> mathematical formalism? > > It's as close to a mathematician's notion of a monad as Haskell's > types and functions are to the objects and arrows of category theory. Right. So it's a pretty close correspondence. > http://en.wikipedia.org/wiki/Monad_%28category_theory%29 "Monads are important in the theory of pairs of adjoint functors. They can be viewed as monoid objects in a category of endofunctors (hence the name) and they generalize closure operators on posets to arbitrary categories." *cried softly in the corner* I knew asking questions about theoretical mathematics probably wasn't a good idea... > Knowing that you were about to ask this question I told my past self > by tachyon express and wrote up on it this weekend: > http://sigfpe.blogspot.com/2007/06/monads-from-algebra-and-the-gray-code.html > Heh. *I* would have just told my past self next week's lottery numbers... From gregorypropf at yahoo.com Mon Jul 2 17:02:44 2007 From: gregorypropf at yahoo.com (Gregory Propf) Date: Mon Jul 2 16:56:43 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? Message-ID: <260133.30172.qm@web31405.mail.mud.yahoo.com> Right, I read more about it and found this out. The 'main' function is apparently magical at runtime and allows you to break the with pure functionality just once but since it can call other functions this allows for useful programs to be written. ----- Original Message ---- From: Jules Bean To: Gregory Propf Cc: haskell-cafe@haskell.org Sent: Monday, July 2, 2007 1:40:09 AM Subject: Re: [Haskell-cafe] Re: Parsers are monadic? Gregory Propf wrote: > Thanks, that was helpful. I didn't realize that there were pure > functional monads. Actually, it's stronger than that. All monads are pure functional, even IO. Haskell is an entirely 100% pure functional language[*]. The IO monad allows you to build up, in a pure, referentially transparent way, an object call an 'IO action' which you have no way of actually executing, per se. Fortunately, this isn't as useless as it sounds since the runtime system contains the support to "actually run" the special IO action called 'main', which bootstraps the whole setup. Jules [*] non-functions like unsafePerformIO are not technically part of the haskell language! ____________________________________________________________________________________ Never miss an email again! Yahoo! Toolbar alerts you the instant new Mail arrives. http://tools.search.yahoo.com/toolbar/features/mail/ -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070702/9fa9d39a/attachment.htm From gregorypropf at yahoo.com Mon Jul 2 17:25:57 2007 From: gregorypropf at yahoo.com (Gregory Propf) Date: Mon Jul 2 17:19:55 2007 Subject: [Haskell-cafe] Very simple parser Message-ID: <875413.13110.qm@web31410.mail.mud.yahoo.com> As a programming exercise I'm trying to use the State monad to create a simple parser. It's for a very simple assembly language for a simple virtual machine. The state is a string of instructions. I want to be able to call something like getNextInstruction to pull out the next instruction and then update the state (string). I know I can do this non-monadically by just passing the string explicitly each time but I'd like to learn more about the State monad. I also know about Parsec and Happy and so forth but this is just an exercise so I want to do it this way. Any ideas? I can't seem to get anything to work. I've tried different things but I suspect I'm just missing something basic. Can someone post a simple prototype for this? Just assume the instructions are integers. ____________________________________________________________________________________ Get the Yahoo! toolbar and be alerted to new email wherever you're surfing. http://new.toolbar.yahoo.com/toolbar/features/mail/index.php -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070702/c92bcaa0/attachment-0001.htm From ariep at xs4all.nl Mon Jul 2 17:38:41 2007 From: ariep at xs4all.nl (Arie Peterson) Date: Mon Jul 2 17:32:37 2007 Subject: [Haskell-cafe] Re: Parsers are monadic? In-Reply-To: <260133.30172.qm@web31405.mail.mud.yahoo.com> References: <260133.30172.qm@web31405.mail.mud.yahoo.com> Message-ID: <16465.213.84.177.94.1183412321.squirrel@webmail.xs4all.nl> Gregory Propf wrote: > Right, I read more about it and found this out. The 'main' function is > apparently magical at runtime and allows you to break the with pure > functionality just once but since it can call other functions this allows > for useful programs to be written. There is more than one way to look at this, but I wouldn't say purity is broken, not even by the main function. You can think of an IO action as an 'execution plan', containing detailed instructions on obtaining input, applying functions, branching, creating output, etc. The compiler takes the 'main' execution plan, and creates a program that will actually perform it. As a programmer, you only compose execution plans, which is nice and pure. Kind regards, Arie From ariep at xs4all.nl Mon Jul 2 17:46:14 2007 From: ariep at xs4all.nl (Arie Peterson) Date: Mon Jul 2 17:40:10 2007 Subject: [Haskell-cafe] Very simple parser In-Reply-To: <875413.13110.qm@web31410.mail.mud.yahoo.com> References: <875413.13110.qm@web31410.mail.mud.yahoo.com> Message-ID: <9241.213.84.177.94.1183412774.squirrel@webmail.xs4all.nl> Gregory Propf wrote: > As a programming exercise I'm trying to use the State monad to create a > simple parser. It's for a very simple assembly language for a simple > virtual machine. The state is a string of instructions. I want to be > able to call something like getNextInstruction to pull out the next > instruction and then update the state (string). I know I can do this > non-monadically by just passing the string explicitly each time but I'd > like to learn more about the State monad. I also know about Parsec and > Happy and so forth but this is just an exercise so I want to do it this > way. Any ideas? I can't seem to get anything to work. I've tried > different things but I suspect I'm just missing something basic. Can > someone post a simple prototype for this? Just assume the instructions > are integers. Did you look at the documentation for the State monad? It also contains some examples. Getting the next instruction sounds like a job for 'get'; to remove it from the state you might use 'put' or 'modify'. If this doesn't help, can you show something you tried? Greetings, Arie From jcast at ou.edu Mon Jul 2 17:48:21 2007 From: jcast at ou.edu (Jonathan Cast) Date: Mon Jul 2 17:42:31 2007 Subject: [Haskell-cafe] Before In-Reply-To: <4689374D.3050909@btinternet.com> References: <4689374D.3050909@btinternet.com> Message-ID: <200707021648.23781.jcast@ou.edu> On Monday 02 July 2007, Andrew Coppin wrote: > What were monads like before they became a Haskell language construct? > > Is Haskell's idea of a "monad" actually anywhere close to the original > mathematical formalism? > > Just being randomly curiose... Curiosity can be a dangerous thing . . . Short answer: they're equivalent, or rather, Haskell monads are equivalent to what Haskellers would naturally write when translating mathematical monads into Haskell. If you really want to know the details (it's a fascinating subject once you start understanding it), go read a couple or three good books on category theory; I'm sure someone else here can give you a better reading list than I can off the top of my head. Building up to the idea of a monad in category theory, with proper examples and whatnot, requires a full textbook; in particular, /Toposes, Triples, and Theories/, where I learned the concept and which wants to actually do something interesting with them, is required to compress the categorical preliminaries to a point where I needed constant reference to other books just to understand the basic concepts. Nevertheless, if you really want the high points: Monads come from a branch of abstract mathematics called /category theory/, which was invented, originally, to provide a mathematical characterization of polymorphic functions (or, rather, of the uniform nature of certain functions, which FPers would characterize as a form of polymorphism). A category is a 6-tuple (objects, arrows, domain, codomain, id, compose) where objects and arrrows are arbitrary classes, domain and codomain are mappings from arrows to objects, id is a mapping from objects to arrows such that domain (id alpha) = alpha codomain (id alpha) = alpha and compose is an associative partial binary operator on arrows with the images of id as units, such that compose f g is defined whenever domain f = codomain g, and domain (compose f g) = domain g codomain (compose f g) = codomain f Following standard practice, I will write f : alpha -> beta for domain f = alpha codomain f = beta and f . g for compose f g. (Standard practice in category theory is I believe to write composition as juxtaposition (like application in Haskell, but associative), but I'm not going that far to make the notation look more Haskell-like). Given that A and B are categories, a /functor/ F from A to B is a pair of mappings (F_objects, F_arrows) (both generally written F in practice) from objects of A to objects of B and arrows of A to arrows of B, respectively, such that domain (F a) = F (domain a) codomain (F a) = F (codomain a) compose (F a) (F b) = F (compose a b) id (F a) = F (id a) Given two functors, F, G : A -> B, a natural transformation h : F -> G is a mapping h from objects of A to arrows of B such that h alpha : F alpha -> G alpha h beta . F f = F f . h alpha (forall f : alpha -> beta) Given a category C, a monad in C is a triple (F, eta, mu) of a functor F : C -> C, a natural transformation eta : Id -> F, where Id is the identity functor, and a natural transformation mu : F . F -> F, where composition of functors is defined component-wise, satisfying the additional laws mu . F mu = mu . mu mu . eta = id = mu . F eta When translating category theory into Haskell, objects are taken to be types and arrows functions; domain, codomain, id, and compose are defined the way you would expect. A functor is represented by class Functor in the standard prelude; an instance consists of a data type constructor F, which is the only mapping on types supported by Haskell, and a function fmap :: (alpha -> beta) -> (F alpha -> F beta) (remember currying!) corresponding to the arrow map. A natural transformation is a polymorphic function f :: F alpha -> G alpha such that fmap g . f = f . fmap g for all functions g. This is (at least sometimes) provable for arbitrary polymorphic functions (as long as they don't use seq!), but I'm not sure of the details of this. At any rate, doing so isn't certainly isn't necessary. Translating the definition of a monad into Haskell using this terminology would give us class Functor m => Monad m where return :: alpha -> m alpha join :: m (m alpha) -> m alpha (join, by the way, is one of the most under-appreciated of Haskell library functions; learning it is necessary both for true mastery of Haskell monads). The complete collection of class laws (including the natural transformation laws) is fmap g . return = return . g fmap g . join = join . fmap (fmap g) join . fmap join = join . join join . return = id = join . fmap return (Note the essential similarity of these laws to those given above). Haskell, of course, actually gives us class Monad m where return :: alpha -> m alpha (>>=) :: m alpha -> (alpha -> m beta) -> m beta The relationship between these two signatures is given by the set of equations fmap f a = a >>= return . f join a = a >>= id a >>= f = join (fmap f a) and the monad laws in Haskell are return x >>= f = f x a >>= return = a (a >>= f) >>= g = a >>= \ x -> f x >>= g We can take the relationship given above as definitional, in either direction, and derive the appropriate set of laws. Taking fmap and join as primitive, we get return x >>= f = join (fmap f (return x)) = join (return (f x)) = f x a >>= return = join (fmap return a) = a (a >>= f) >>= g = join (fmap g (join (fmap f a))) = join (join (fmap (fmap g) (fmap f a))) = join (fmap join (fmap (fmap g) (fmap f a))) = join (fmap (join . fmap g . f) a) = a >>= join . fmap g . f = a >>= \ x -> join (fmap g (f x)) = a >>= \ x -> f x >>= g Taking (>>=) as primitive, we get fmap f (return x) = return x >>= return . f = return (f x) fmap f (join a) = (a >>= id) >>= return . f = a >>= \ x -> id x >>= return . f = a >>= \ x -> x >>= return . f = a >>= fmap f = a >>= \ x -> id (fmap f x) = a >>= \ x -> return (fmap f x) >>= id = (a >>= return . fmap f) >>= id = join (fmap (fmap f) a) join (join a) = (a >>= id) >>= id = a >>= \ x -> x >>= id = a >>= \ x -> join x = a >>= \ x -> return (join x) >>= id = (a >>= return . join) >>= id = join (fmap join a) join (return a) = return a >>= id = id a = a join (fmap return a) = (a >>= return . return) >>= id = a >>= \ x -> return (return x) >>= id = a >>= \ x -> return x = a >>= return = a This is less general than the category theory version, and seq creates problems with some of these equations (or at least with proving that any of them hold for real programs!), but using the normal methods of Haskell equational reasoning (assume all values are total and finite, all functions preserve totality and finiteness, and the context preserves totality and finiteness, and using = on functions to mean equality on total and finite arguments), it works; Haskell monads are just an alternative formulation for a (not-quite-semantics-preseving) transliteration of category theory monads into the Haskell setting. Jonathan Cast http://sourceforge.net/projects/fid-core http://sourceforge.net/projects/fid-emacs From stefanor at cox.net Mon Jul 2 18:12:40 2007 From: stefanor at cox.net (Stefan O'Rear) Date: Mon Jul 2 18:06:40 2007 Subject: [Haskell-cafe] Very simple parser In-Reply-To: <875413.13110.qm@web31410.mail.mud.yahoo.com> References: <875413.13110.qm@web31410.mail.mud.yahoo.com> Message-ID: <20070702221240.GA6078@localhost.localdomain> vim: set ft=lhaskell: On Mon, Jul 02, 2007 at 02:25:57PM -0700, Gregory Propf wrote: | As a programming exercise I'm trying to use the State monad to create | a simple parser. It's for a very simple assembly language for a | simple virtual machine. The state is a string of instructions. I | want to be able to call something like getNextInstruction to pull out | the next instruction and then update the state (string). I know I can | do this non-monadically by just passing the string explicitly each | time but I'd like to learn more about the State monad. I also know | about Parsec and Happy and so forth but this is just an exercise so I | want to do it this way. Any ideas? I can't seem to get anything to | work. I've tried different things but I suspect I'm just missing | something basic. Can someone post a simple prototype for this? Just | assume the instructions are integers. For an example, here is the simplest parser type I know of; LL(1) a la Crenshaw. Our parser is simply a stateful computation using the rest of the input. > import Char > import Control.Monad.State > type P = State [Char] Simple primitives. We need to be able to see what the next character is. Notice that we return Maybe because there might not be a next character. Also note the use of the State data constructor to modify the value and return at the same time. > look :: P (Maybe Char) > look = State $ \ st -> case st of > [] -> (Nothing, []) > (c:cs) -> (Just c, c:cs) We need to do tests occasionally on the values. > isDigit' = maybe False isDigit > digitToInt' = maybe 0 digitToInt getc is similar, but it removes the character. This is typically done after making a decision based on look. > getc :: P (Maybe Char) > getc = State $ \ st -> case st of > [] -> (Nothing, []) > (c:cs) -> (Just c, cs) If we find inconsistent input, we signal a fatal error using the fail function already defined for State. A more featureful monad such as ErrorT (State [Char]) could be used to make error conditions non-fatal for the program. Often, we know what the lookahead will be; we can use this for better error messages. (We should also store the text position in the state, but for pedagogical reasons I will ignore that). For instance, if we are expecting something but don't find it, we use expected: > expected str = do > context <- gets (show . take 20) > fail $ str ++ " expected; found " ++ context ++ " instead" Skipping whitespace is very important to handle our lines. Note that we also handle #-comments. > white = look >>= \ch -> > case ch of Just '#' -> line >> white > Just ' ' -> getc >> white > Just '\t' -> getc >> white > _ -> return () > > line = look >>= \ch -> > case ch of Just '\n' -> return () > Nothing -> return () > _ -> getc >> line Another common pattern is to skip over a noise character while verifying that it was correct. Notice the use of expected to handle error message formatting. Also note that we skip whitespace afterward - from here on we will maintain the invariant that the cursor does not point to spaces. > match ch = look >>= \realch -> > if (realch == Just ch) > then getc > else expected (show ch) Parsing integers is one of the problem requirements; it is handled by dispatching on the first character, then parsing a natural. > number = look >>= \ch -> case ch of > Just '+' -> match '+' >> natural 0 > Just '-' -> match '-' >> negate `fmap` natural 0 > _ -> natural 0 Naturals can be handled using a simple loop. Notice that we check lookahead at the *end*, this is necessary to avoid parsing eg "xx" as a natural 0. We use an accumulating parameter. > natural acc = look >>= \ch -> do > unless (isDigit' ch) $ expected "number" > > getc > let acc' = digitToInt' ch + acc * 10 > > look >>= \lk -> if isDigit' lk > then natural acc' > else white >> return acc' A line of input to our assembler consists of horizontal whitespace, an optional number, more horizontal whitespace, and a newline. > inputLine = do > white > look >>= \ch -> if isDigit' ch > then do number > white > else return () > match '\n' All our input consists of input lines for as long as there is more. > input = look >>= maybe (return ()) (\_ -> inputLine >> input) > main = interact $ show . runState input Stefan From hughperkins at gmail.com Mon Jul 2 18:20:40 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Mon Jul 2 18:14:38 2007 Subject: [Haskell-cafe] Getting debugging/logging info? Message-ID: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> In imperative languages we can do this type of thing: SystemLogging.LogInfo("About to do something..."); DoSomething(); SystemLogging.LogInfo("Did Something"); SystemLogging.LogInfo("x is " + x ); How can we do something similar in Haskell? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070703/a07d4186/attachment.htm From hughperkins at gmail.com Mon Jul 2 18:26:47 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Mon Jul 2 18:20:46 2007 Subject: [Haskell-cafe] Callback functions? Message-ID: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> This sounds something like using a continuation function. In imperative languages, we might have something like: class MyDisplayForm { void ButtonGo_Press() { Processor.Go( new CallbackDelegate( this.SetStatus ) ); } public void SetStatus( string message ) { StatusLbl.Text = message; Application.DoEvents(); } } So: we call Processor.Go, passing in a pointer to the function SetStatus (a "delegate" in C# terminology, an "interface" in Java, a pointer in C, ...). The Processor.Go function is going to update the status bar in MyDisplayForm as it goes along with useful messages "Processing blah.txt...", etc. It does that by calling the passed in "callback" function, with the appropriate status message as a parameter. This is also implicit to the Observer pattern, which may or may not be useful in FP (?) Anyway, so the question is: how do we write callback functions in FP/Haskell? Can someone provide a simple, but functional example? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070703/32220329/attachment.htm From dpiponi at gmail.com Mon Jul 2 18:33:26 2007 From: dpiponi at gmail.com (Dan Piponi) Date: Mon Jul 2 18:27:25 2007 Subject: [Haskell-cafe] Callback functions? In-Reply-To: <625b74080707021532g1028b877pb53d7f214827fd6e@mail.gmail.com> References: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> <625b74080707021532g1028b877pb53d7f214827fd6e@mail.gmail.com> Message-ID: <625b74080707021533q2b9ed37etb2273197cad1f514@mail.gmail.com> On 7/2/07, Hugh Perkins wrote: > Anyway, so the question is: how do we write callback functions in > FP/Haskell? Can someone provide a simple, but functional example? What makes a callback different from any other kind of function? In Haskell, as in other functional programming languages, you're completely free to pass functions into other functions and store them in datastructures. Take a look at the 'callbacks' used in the HOpenGL examples. They're just ordinary functions: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/libraries/GLUT/examples/RedBook/ -- Dan From stefanor at cox.net Mon Jul 2 18:34:03 2007 From: stefanor at cox.net (Stefan O'Rear) Date: Mon Jul 2 18:28:03 2007 Subject: [Haskell-cafe] Callback functions? In-Reply-To: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> References: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> Message-ID: <20070702223403.GA6192@localhost.localdomain> On Tue, Jul 03, 2007 at 12:26:47AM +0200, Hugh Perkins wrote: > This sounds something like using a continuation function. > > In imperative languages, we might have something like: > > class MyDisplayForm > { > void ButtonGo_Press() > { > Processor.Go( new CallbackDelegate( this.SetStatus ) ); > } > > public void SetStatus( string message ) > { > StatusLbl.Text = message; > Application.DoEvents(); > } > } > > > So: we call Processor.Go, passing in a pointer to the function SetStatus (a > "delegate" in C# terminology, an "interface" in Java, a pointer in C, ...). > > The Processor.Go function is going to update the status bar in MyDisplayForm > as it goes along with useful messages "Processing blah.txt...", etc. > > It does that by calling the passed in "callback" function, with the > appropriate status message as a parameter. > > This is also implicit to the Observer pattern, which may or may not be > useful in FP (?) > > > Anyway, so the question is: how do we write callback functions in > FP/Haskell? Can someone provide a simple, but functional example? mapM_ print [1,2,3] But usually we don't do that, because returning the list directly is simpler and because of laziness, almost as fast. Stefan From gregorypropf at yahoo.com Mon Jul 2 18:37:52 2007 From: gregorypropf at yahoo.com (Gregory Propf) Date: Mon Jul 2 18:31:49 2007 Subject: [Haskell-cafe] Very simple parser Message-ID: <690904.53683.qm@web31404.mail.mud.yahoo.com> I hadn't seen that before, thanks. My code wouldn't be that useful as it depends on some of my datatypes. I don't know some basic things here since I'm so new to Haskell. For example, am I to assume that I need to create my own instance of State and then define get and put for it? Some of the examples seem to just use functions that manipulate a state but do not create a new datatype. ----- Original Message ---- From: Arie Peterson To: haskell-cafe@haskell.org Sent: Monday, July 2, 2007 2:46:14 PM Subject: Re: [Haskell-cafe] Very simple parser Did you look at the documentation for the State monad? It also contains some examples. Getting the next instruction sounds like a job for 'get'; to remove it from the state you might use 'put' or 'modify'. If this doesn't help, can you show something you tried? Greetings, Arie _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe ____________________________________________________________________________________ Take the Internet to Go: Yahoo!Go puts the Internet in your pocket: mail, news, photos & more. http://mobile.yahoo.com/go?refer=1GNXIC -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070702/4b3128fe/attachment.htm From ndmitchell at gmail.com Mon Jul 2 18:40:48 2007 From: ndmitchell at gmail.com (Neil Mitchell) Date: Mon Jul 2 18:34:44 2007 Subject: [Haskell-cafe] Getting debugging/logging info? In-Reply-To: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> References: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> Message-ID: <404396ef0707021540p5c2e0c73qb244f65b0d5ff640@mail.gmail.com> Hi > SystemLogging.LogInfo("Did Something"); > SystemLogging.LogInfo("x is " + x ); > > How can we do something similar in Haskell? See trace: http://www.haskell.org/hoogle/?q=trace Thanks Neil From mark at ixod.org Mon Jul 2 18:45:06 2007 From: mark at ixod.org (Mark T.B. Carroll) Date: Mon Jul 2 18:39:12 2007 Subject: [Haskell-cafe] Getting debugging/logging info? In-Reply-To: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> (Hugh Perkins's message of "Tue, 3 Jul 2007 00:20:40 +0200") References: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> Message-ID: <874pkmbf2l.fsf@ixod.org> "Hugh Perkins" writes: > SystemLogging.LogInfo("About to do something..."); > DoSomething(); > SystemLogging.LogInfo("Did Something"); > SystemLogging.LogInfo("x is " + x ); > > How can we do something similar in Haskell? Maybe, with System.IO, main = do log <- openFile "/tmp/log.txt" AppendMode hSetBuffering log LineBuffering hPutStrLn log "About to do something..." x <- return $! product [1 .. 65536] hPutStrLn log "did something." hPutStrLn log ("x is " ++ show x) hClose log Others may now correct me. (-: -- Mark From hughperkins at gmail.com Mon Jul 2 18:46:51 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Mon Jul 2 18:40:49 2007 Subject: [Haskell-cafe] Very simple parser In-Reply-To: <20070702221240.GA6078@localhost.localdomain> References: <875413.13110.qm@web31410.mail.mud.yahoo.com> <20070702221240.GA6078@localhost.localdomain> Message-ID: <837db430707021546g29876940nb62b51a7a9d9ede5@mail.gmail.com> Graham Hutton has some great tutorials on parsing. Check out the "Are parsers monodic?" thread (not exact name) for a good reference. There's also a good tutorial at http://www.cs.nott.ac.uk/~gmh/book.html In Section "Slides", click on "8 Functional parsers", but you may just want to start from 1. They're really quick and painless. Graham Hutton's tutorials are about the only tutorials on monads that make sense to me. YMMV of course. Other than that... a list is an instance of State, I think (?), so you can do something like (writing this in directly, without trying to compile): processor :: State a processor = do value <- gets head case value of "blah" -> return blah "foo" -> return foo dotest = evalState( processor )["blah","foo"] Note that I'm a total newbie, and I didnt check this compiles (almost certainly doesnt) so take this with a wodge of salt I cant say I really like the way I have a case that selects on strings to decide which function to call. If someone knows a more elegant/spelling-safe way of doing this that'd be really useful generally. For example something like this could be more spelling safe (if it worked) (maybe it does???): case value of (showConstr $ toConstr $ blah) -> return blah (showConstr $ toConstr $ foo) -> return foo -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070703/77830168/attachment.htm From hughperkins at gmail.com Mon Jul 2 18:50:07 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Mon Jul 2 18:44:05 2007 Subject: [Haskell-cafe] Getting debugging/logging info? In-Reply-To: <874pkmbf2l.fsf@ixod.org> References: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> <874pkmbf2l.fsf@ixod.org> Message-ID: <837db430707021550m7b7b0ddeqa560018858923116@mail.gmail.com> On 7/3/07, Neil Mitchell wrote: > > See trace: http://www.haskell.org/hoogle/?q=trace > > I'll check that out. Thanks. > Maybe, with System.IO, Fine in main :-) Less good in a 100,000 line application. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070703/634b6630/attachment.htm From mark at ixod.org Mon Jul 2 18:57:13 2007 From: mark at ixod.org (Mark T.B. Carroll) Date: Mon Jul 2 18:51:19 2007 Subject: [Haskell-cafe] Getting debugging/logging info? In-Reply-To: <837db430707021550m7b7b0ddeqa560018858923116@mail.gmail.com> (Hugh Perkins's message of "Tue, 3 Jul 2007 00:50:07 +0200") References: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> <874pkmbf2l.fsf@ixod.org> <837db430707021550m7b7b0ddeqa560018858923116@mail.gmail.com> Message-ID: <87ved29zxy.fsf@ixod.org> "Hugh Perkins" writes: (snip) >> Maybe, with System.IO, > > Fine in main :-) Less good in a 100,000 line application. Oh, sorry, I thought your point had been about making sure the operation was done before the "did something" line got printed. (-: -- Mark From hughperkins at gmail.com Mon Jul 2 19:00:04 2007 From: hughperkins at gmail.com (Hugh Perkins) Date: Mon Jul 2 18:54:01 2007 Subject: [Haskell-cafe] Callback functions? In-Reply-To: <625b74080707021533q2b9ed37etb2273197cad1f514@mail.gmail.com> References: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> <625b74080707021532g1028b877pb53d7f214827fd6e@mail.gmail.com> <625b74080707021533q2b9ed37etb2273197cad1f514@mail.gmail.com> Message-ID: <837db430707021600i17207bc9p6403fbe12bab6b10@mail.gmail.com> > http://cvs.haskell.org/cgi-bin > > /cvsweb.cgi/fptools/libraries/GLUT/examples/RedBook/ Ok, I'll take a look > What makes a callback different from any other kind of function? Well... what about inside monads? Does this break purity??? Does this require adding IO to the monad if the callback function does IO? As I'm writing this I kindof have this sense inside me that this is a really newbie-ish question. That the answer is no it doesnt break purity, yes it does require adding IO to the monad, but I'm asking anyway just to check :-) On 7/3/07, Dan Piponi wrote: > > On 7/2/07, Hugh Perkins wrote: > > > Anyway, so the question is: how do we write callback functions in > > FP/Haskell? Can someone provide a simple, but functional example? > > What makes a callback different from any other kind of function? In > Haskell, as in other functional programming languages, you're > completely free to pass functions into other functions and store them > in datastructures. Take a look at the 'callbacks' used in the HOpenGL > examples. They're just ordinary functions: > > http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/libraries/GLUT/examples/RedBook/ > -- > Dan > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070703/8b6af975/attachment-0001.htm From allbery at ece.cmu.edu Mon Jul 2 19:04:51 2007 From: allbery at ece.cmu.edu (Brandon S. Allbery KF8NH) Date: Mon Jul 2 18:58:54 2007 Subject: [Haskell-cafe] Getting debugging/logging info? In-Reply-To: <404396ef0707021540p5c2e0c73qb244f65b0d5ff640@mail.gmail.com> References: <837db430707021520k1ca6f0f1wf16c6136c4bd7975@mail.gmail.com> <404396ef0707021540p5c2e0c73qb244f65b0d5ff640@mail.gmail.com> Message-ID: <6EFBEC6E-9190-4C18-9FA1-B86FE65E1F35@ece.cmu.edu> On Jul 2, 2007, at 18:40 , Neil Mitchell wrote: >> SystemLogging.LogInfo("Did Something"); >> SystemLogging.LogInfo("x is " + x ); >> >> How can we do something similar in Haskell? > > See trace: http://www.haskell.org/hoogle/?q=trace In addition, you could use the Writer monad to collect log information as you perform a computation. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH From dpiponi at gmail.com Mon Jul 2 19:48:13 2007 From: dpiponi at gmail.com (Dan Piponi) Date: Mon Jul 2 19:42:10 2007 Subject: [Haskell-cafe] Callback functions? In-Reply-To: <837db430707021600i17207bc9p6403fbe12bab6b10@mail.gmail.com> References: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> <625b74080707021532g1028b877pb53d7f214827fd6e@mail.gmail.com> <625b74080707021533q2b9ed37etb2273197cad1f514@mail.gmail.com> <837db430707021600i17207bc9p6403fbe12bab6b10@mail.gmail.com> Message-ID: <625b74080707021648h51f212dfs82e27f72360f8f8b@mail.gmail.com> On 7/2/07, Hugh Perkins wrote: > Well... what about inside monads? Does this break purity??? Does this > require adding IO to the monad if the callback function does IO? Check out the documentation for the HOpenGL callbacks here: http://www.haskell.org/HOpenGL/documentation/GLUT/Graphics.UI.GLUT.Callbacks.Window.html#v%3AsetDisplayCallback. I think they do exactly what you are talking about in terms of doing I/O. If, the callback needs to perform I/O then the callback itself will likely be a function that returns an instance of IO, just like any other function that does I/O. Any function that calls the callback will likely also return an instance of IO because if a function is 'tainted' by IO, then so are its callers (usually). But in a sense you don't really need to talk about callbacks in Haskell because passing functions into other functions so that they can be called is the norm rather than the exception in Haskell. You don't need to give them a special name. (The HOpenGL API probably does so because it's inheriting from an underlying C API that calls them callbacks.) -- Dan From ariep at xs4all.nl Mon Jul 2 19:51:59 2007 From: ariep at xs4all.nl (Arie Peterson) Date: Mon Jul 2 19:45:54 2007 Subject: [Haskell-cafe] Very simple parser In-Reply-To: <690904.53683.qm@web31404.mail.mud.yahoo.com> References: <690904.53683.qm@web31404.mail.mud.yahoo.com> Message-ID: <7565.213.84.177.94.1183420319.squirrel@webmail.xs4all.nl> Gregory Propf wrote: | [...] For example, am I to assume that I need to | create my own instance of State and then define get and put for it? No, there is a 'State s' monad provided (for arbitrary state type 's'), which implements the 'get' and 'put' methods. In other words, 'State s' is an instance of the 'MonadState s' class. This terminology can be really confusing at first. For now, you may forget about the MonadState class. Simply use 'get' & friends and everything will work fine. To get you going, start with the example from the documentation, modified slightly: > tick :: State Int String > tick = do > n <- get > put (n+1) > return (show n) If you want to actually run 'tick', use the 'runState' function: > runTick :: Int -> (String,Int) > runTick = runState tick The argument of 'runTick' is used as initial state. The returned String is the return value, the Int is the final state. Now, put this code in a module and load it in an interpreter (ghci, hugs,...). Unleash 'runTick' on an integer number of your choice, and convince yourself that the result is what you would expect from the definition of 'tick'. Next, try to make some variants of 'tick': replace the return value by something else, or use a list [Int] as state, instead of a single number. Shout if you need more or other help. Kind regards, Arie From gregorypropf at yahoo.com Mon Jul 2 20:33:12 2007 From: gregorypropf at yahoo.com (Gregory Propf) Date: Mon Jul 2 20:27:09 2007 Subject: [Haskell-cafe] Very simple parser Message-ID: <43077.90434.qm@web31404.mail.mud.yahoo.com> This was a bit baffling too. It appears that there's an implied argument to runTick. This also works and makes it more explicit. I suppose the compiler just works out that the only place to put the 'n' is after tick. runTick :: Int -> (String,Int) runTick n = runState tick n ----- Original Message ---- From: Arie Peterson To: haskell-cafe@haskell.org Sent: Monday, July 2, 2007 4:51:59 PM Subject: Re: [Haskell-cafe] Very simple parser To get you going, start with the example from the documentation, modified slightly: > tick :: State Int String > tick = do > n <- get > put (n+1) > return (show n) If you want to actually run 'tick', use the 'runState' function: > runTick :: Int -> (String,Int) > runTick = runState tick ____________________________________________________________________________________ Sucker-punch spam with award-winning protection. Try the free Yahoo! Mail Beta. http://advision.webevents.yahoo.com/mailbeta/features_spam.html -------------- next part -------------- An HTML attachment was scrubbed... URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070702/3a4fe967/attachment.htm From catamorphism at gmail.com Mon Jul 2 20:37:41 2007 From: catamorphism at gmail.com (Tim Chevalier) Date: Mon Jul 2 20:31:37 2007 Subject: [Haskell-cafe] Very simple parser In-Reply-To: <43077.90434.qm@web31404.mail.mud.yahoo.com> References: <43077.90434.qm@web31404.mail.mud.yahoo.com> Message-ID: <4683d9370707021737r4e2fb615kd871f67c3f2528d@mail.gmail.com> On 7/2/07, Gregory Propf wrote: > > > > This was a bit baffling too. It appears that there's an implied argument to runTick. This also works and makes it more explicit. I suppose the compiler just works out that the only place to put the 'n' is after tick. > > runTick :: Int -> (String,Int) > runTick n = runState tick n > Not exactly. Look up "currying". (Writing out the same definition with the argument "n" specified explicitly like you did is called "eta-expansion", by the way.) Cheers, Tim -- Tim Chevalier* catamorphism.org *Often in error, never in doubt "My writing is all completely autobiographical. That's why I write lesbian vampire stories." -- Jewelle Gomez From trebla at vex.net Mon Jul 2 20:49:48 2007 From: trebla at vex.net (Albert Y. C. Lai) Date: Mon Jul 2 20:43:48 2007 Subject: [Haskell-cafe] Callback functions? In-Reply-To: <837db430707021600i17207bc9p6403fbe12bab6b10@mail.gmail.com> References: <837db430707021526r42488febw3e61fcde15872a0c@mail.gmail.com> <625b74080707021532g1028b877pb53d7f214827fd6e@mail.gmail.com> <625b74080707021533q2b9ed37etb2273197cad1f514@mail.gmail.com> <837db430707021600i17207bc9p6403fbe12bab6b10@mail.gmail.com> Message-ID: <46899D2C.9080500@vex.net> Hugh Perkins wrote: > > What makes a callback different from any other kind of function? > > Well... what about inside monads? Does this break purity??? Does this > require adding IO to the monad if the callback function does IO? > > As I'm writing this I kindof have this sense inside me that this is a > really newbie-ish question. That the answer is no it doesnt break > purity, yes it does require adding IO to the monad, but I'm asking > anyway just to check :-) The question exists only because of a cultural difference. Let f, g be functions (actions, procedures, methods, subroutines...) such that "f(g)" is legal and means f may invoke g. Mainstream programmers say g is a callback function, f is a function that accepts a callback function. Functional programmers say f is a higher-order function, g is a function. Its use is pervasive in functional programming and especially Haskell. Already in the second or third lesson, one meets map h [1,2,3] foldl (+) 0 [1,2,3] where map calls h, and foldl calls (+). It does not matter that all of them are pure functions, since, in mainstream programming, g is still a callback function whether pure or side-effecting, cf. qsort and bsearch in C. Some callback functions are intended to be side-effecting. To do IO actions and handle exceptions, we write like catch my_action my_handler catch calls my_action; if an exception is raised, catch furthermore calls my_handler. Thus my_action and my_handler are callbacks, and catch is a higher-order function. This is remarkably different culturally from mainstream programming: In mainstream programming, exception handling is a special syntax, not a library function taking handlers as callbacks (let alone the major action); in Haskell programming, exception handling is just another higher-order function, not a special syntax. It doesn't stop there. Whenever you write do a <- m n a which is desugared to m >>= \a