|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 | Next > |
|
|
Re: Re: Doubting Haskell>>>>> "apfelmus" == apfelmus <apfelmus@...> writes:
apfelmus> Colin Paul Adams wrote: >> Left? Right? >> >> Hardly descriptive terms. Sounds like a sinister language to >> me. apfelmus> The mnemonics is that Right x is "right" in the sense of apfelmus> correct. So, the error case has to be Left err . As I said, this is sinister (i.e. regarding left-handed people as evil). And left is not the opposite of correct. That would be incorrect. Also, it is not clear to me that a failure to read a file (for instance) is incorrect behaviour. If the file doesn't exist, then I think it ought to be considered correct behaviour to fail to read the file. So Success and Failure seem to be much better. Certainly they make the program far more readable to my eyes. -- Colin Adams Preston Lancashire _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Re: Doubting HaskellOn 17 Feb 2008, at 1:12 AM, Colin Paul Adams wrote: >>>>>> "apfelmus" == apfelmus <apfelmus@...> writes: > > apfelmus> Colin Paul Adams wrote: >>> Left? Right? >>> >>> Hardly descriptive terms. Sounds like a sinister language to >>> me. > > apfelmus> The mnemonics is that Right x is "right" in the sense of > apfelmus> correct. So, the error case has to be Left err . > > As I said, this is sinister You do know what `sinister' means, no? > (i.e. regarding left-handed people as > evil). Sheesh, it's just a mnemonic... > > And left is not the opposite of correct. That would be incorrect. No, Left is the opposite of Right. Right is the constructor modified by fmap (due to the design of Haskell type classes); therefore return = Right. Therefore any computation in Either that is not the result of a return is an application of Left. > Also, it is not clear to me that a failure to read a file (for > instance) is incorrect behaviour. Then don't think of Left as `incorrect behavior'. Left isn't incorrect, or Parsec's parse function wouldn't return it on parse errors. > If the file doesn't exist, then I > think it ought to be considered correct behaviour to fail to read the > file. > > So Success and Failure seem to be much better. Certainly they make the > program far more readable to my eyes. But the program succeeded in doing what I expected it to do when if failed... jcc Besides, these decisions were made 15 years ago, they're not going to change now... _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellAlan Carter wrote:
> We now need to be able to do parallel with ease. Functional > programming just got really important. While this is a reason to have a look at Haskell, I think it's not the best one. In fact, I think it's probably harmful to have parallelism as single goal for learning Haskell: the language is very different from imperative languages and if you "just want to do parallelism" but otherwise stick to what you know, you'll have a really hard time. > Eventually a 3 page > introduction on the O'Reilly website together with a good document > called "Haskell for C Programmers" got me to the point where I could > access "Yet Another Haskell Tutorial", and I was away... for a bit. IMHO, the easiest way to learn Haskell and to appreciate functional programming is to learn it from a textbook :) The online tutorials are nice but you'll have a much harder time with them. I'd recommend Hutton's "Programming in Haskell" for the basics and Bird's "Introduction to Functional Programming using Haskell" for the functional style. See also http://haskell.org/haskellwiki/Books#Textbooks Of course, the textbooks (except "Real World Haskll" which is not done yet) most likely don't cover the System.IO stuff, but you've got the #haskell irc channel and the mailing list for that. So, the textbook remark is in anticipation of the questions that you are going to have :) (if you decide to pursue Haskell further, that is). Regards, apfelmus _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellOn 17 feb 2008, at 08.46, Anton van Straaten wrote: > Colin Paul Adams wrote: >>>>>>> "Cale" == Cale Gibbard <cgibbard@...> writes: >> Cale> So, the first version: >> Cale> import System.IO import Control.Exception (try) >> Cale> main = do mfh <- try (openFile "myFile" ReadMode) case mfh >> Cale> of Left err -> do putStr "Error opening file for reading: " >> Cale> print err Right fh -> do mline <- try (hGetLine fh) case >> Cale> mline of Left err -> do putStr "Error reading line: " print >> Cale> err hClose fh Right line -> putStrLn ("Read: " ++ line) >> Left? Right? >> Hardly descriptive terms. Sounds like a sinister language to me. > > I was thinking along the same lines. Politically-sensitive left- > handed people everywhere ought to be offended that "Left" is the > alternative used to represent errors, mnemonic value notwithstanding. > > Is there a benefit to reusing a generic Either type for this sort > of thing? For code comprehensibility, wouldn't it be better to use > more specific names? If I want car and cdr, I know where to find it. Haskell doesn't have constructor aliases and keeping around dozens of isomorphic types would be stupid. (Views could help, though.) Also, "Right" is naturally used when the everything was alright. It might be arbitrary, but it's not hard to remember - once you're past the newbie phase no-one confuses car and cdr anyways... _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellOn Sun, 17 Feb 2008, Anton van Straaten wrote:
> Is there a benefit to reusing a generic Either type for this sort of thing? > For code comprehensibility, wouldn't it be better to use more specific > names? If I want car and cdr, I know where to find it. > It's Haskell's standard sum type, with a pile of instances already written. There's an instance of MonadError such that you only need to see an Either when you run the computation for example (and then you get an Either whatever the actual error monad was!). If we had appropriate language extensions to map an isomorphic Success/Failure type onto it then I'd probably use them - as it is, the level of inertia around Either is great enough to mean that's only worth doing if I'm expecting to roll a third constructor in at some point. That said, generally I'll wrap it up pretty fast if I have to handle Either directly. Not that that's necessarily any different to cons, car and cdr of course, but there's plenty of library support for doing so. -- flippa@... "I think you mean Philippa. I believe Phillipa is the one from an alternate universe, who has a beard and programs in BASIC, using only gotos for control flow." -- Anton van Straaten on Lambda the Ultimate _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Re: Doubting HaskellOn Feb 17, 2008, at 1:12 AM, Colin Paul Adams wrote:
> > And left is not the opposite of correct. That would be incorrect. > > Also, it is not clear to me that a failure to read a file (for > instance) is incorrect behaviour. If the file doesn't exist, then I > think it ought to be considered correct behaviour to fail to read the > file. Well, of course correct behavior is to cope with both cases in the most appropriate way. If it's any consolation to those of the left handed persuasion, I guessed it wrong - I have used Either in this way, but Left was Success and Right was Failure. I don't enjoy puns, and mapped to an A/B form it seemed obvious that Success is A. Donn Cave, donn@... _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellDonn Cave writes:
> On Feb 17, 2008, at 1:12 AM, Colin Paul Adams wrote: >> And left is not the opposite of correct. That would be incorrect. ... > If it's any consolation to those of the left handed persuasion, I guessed > it wrong - I have used Either in this way, but Left was Success and > Right was Failure. I don't enjoy puns, and mapped to an A/B form > it seemed obvious that Success is A. Weellll, for those who don't enjoy puns, but feel that the life and everything is one enormous pun, a political reminder. For many years, the world is composed of Leftists and Rightists (let's for the moment forget the normal people). Those from the Left always felt that they were right, and that those from the Right should not be left unpunished, while those from the Right thought that those from the Left should be left to die. Even if it seems right to consider that these deviations should be left to historians, we should not forget that at the beginning of the glorious Soviet country there was a proposal to change the meaning of traffic lights. Red would mean "Forward!!". On the other hand, in France nowadays the difference between Right and Left is more or less the same as between "Immediate failure" and "Delayed failure". Choose yourselves which is which. Jerzy Karczmarczuk _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellHi Alan
I can help but feeling curious. Did some of the answers actually help you? Are you still as doubtful about Haskell as when you wrote your email? Greetings, Mads Lindstrøm _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellOn Sat, Feb 16, 2008 at 05:04:53PM -0800, Donn Cave wrote:
> But in Haskell, you cannot read a file line by line without writing an > exception handler, because end of file is an exception! as if a file does > not normally have an end where the authors of these library functions > came from? Part of it is that using 'getLine' is not idiomatic haskell when you don't want to worry about exceptions. Generally you do something like doMyThing xs = print (length xs) main = do contents <- readFile "my.file" mapM_ doMyThing (lines contents) which will call 'doMyThing' on each line of the file, in this case printing the length of each line. or more succinctly: main = readFile "my.file" >>= mapM_ doMyThing . lines John -- John Meacham - ⑆repetae.net⑆john⑈ _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellBryan O'Sullivan wrote:
> Stefan O'Rear wrote: > >> I'll bet that breaks horribly in the not-so-corner case of /dev/tty. > > Actually, it doesn't. It seems to do a read behind the scenes if the > buffer is empty, so it blocks until you type something. Indeed, and this is why even an unbuffered Handle needs to have a 1-character buffer, an interesting fact I discovered when implementing the I/O library. Cheers, Simon _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Re: Doubting HaskellAm Sonntag, 17. Februar 2008 10:12 schrieb Colin Paul Adams:
> The mnemonics is that Right x is "right" in the sense of > correct. So, the error case has to be Left err . > > As I said, this is sinister (i.e. regarding left-handed people as > evil). I hardly can believe that you mean this seriously. Do you really think that the Haskell architects wanted to offend left-handed people? What does assure you that the names of the Either constructors are about handedness? Are you really so sensitive that you want to make people think about all kinds of misinterpretations the usage of an everyday word may cause before they use it? I’d propose that people don’t search for non-existent defamation so that productivity doesn’t get buried under the search for “politically correct” words. Actually, I wouldn’t have dreamed of Left being related to left-handedness. To me, it has long been very clear that Left and Right were assigned its meaning this way round because otherwise you wouldn’t get Functor and Monad instances. A pure technical reason, having nothing to do with hands, politics and whatever you might think of. > […] Best wishes, Wolfgang _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
|
|
|
Re: Doubting HaskellCale,
On Feb 20, 2008 10:58 AM, Cale Gibbard <cgibbard@...> wrote: > (I'm copying the list on this, since my reply contains a tutorial > which might be of use to other beginners.) Thank you so much for this - I've just started playing with it so few intelligent responses yet. I'm sure it will be of *huge* use to others, right in the middle of the "gap" I fell into. The experiment continues - I'll be back :-) Many thanks, Alan -- ... the PA system was moaning unctuously, like a lady hippopotamus reading A. E. Housman ..." -- James Blish, "They Shall Have Stars" _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellCale Gibbard wrote:
> I woke up rather early, and haven't much to do, so I'll turn this into > a tutorial. :) Cale, this is fantastic, as always. I often find myself searching for material like this when introducing people to Haskell. Would you be willing to put this on the wiki? Thanks, Yitz _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellA quick note here. This is a *really* excellent tutorial on a variety
of subjects. It shows how monad operators can be used responsibly (to clarify code, not obfuscate it), it shows how chosing a good data structure and a good algorithm can work wonders for your code, and on a simplistic level, it shows how to build a database in Haskell. Would it be possible to clean this up and put it in the wiki somewhere? Thanks Bob On 20 Feb 2008, at 09:58, Cale Gibbard wrote: > (I'm copying the list on this, since my reply contains a tutorial > which might be of use to other beginners.) > > On 19/02/2008, Alan Carter <alangcarter@...> wrote: >> Hi Cale, >> >> On Feb 19, 2008 3:48 PM, Cale Gibbard <cgibbard@...> wrote: >>> Just checking up, since you haven't replied on the list. Was my >>> information useful? Did I miss any questions you might have had? If >>> you'd like, I posted some examples of using catch here: >> >> Thanks for your enquiry! My experiment continues. I did put a >> progress >> report on the list - your examples together with a similar long an >> short pair got me over the file opening problem, and taught me some >> things about active whitespace :-) I couldn't get withFile working >> (says out of scope, maybe 'cos I'm ghc 6.6 on my Mac) > > Make sure to put: > > import System.IO > > at the top of your source file, if you haven't been. This should > import everything documented here: > http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-IO.html > >> but it turned out the line I was looking for (collapsed from the >> examples) >> was: >> >> text <- readFile "data.txt" `catch` \_ -> return "" >> >> This ensures the program never loses control, crashing or becoming >> unpredictable by attempting to use an invalid resource, by yielding >> an >> empty String if for any reason the file read fails. Then an empty >> String makes it very quickly through parsing. I guess that's quite >> "functiony" :-) >> >> Amazing how easy once I knew how. Even stranger that I couldn't >> find a >> "bread and butter" example of it. >> >> Then I was going very quickly for a while. My file is dumped from a >> WordPress MySql table. Well formed lines have 4 tab separated fields >> (I'm using pipes for tabs here): >> >> line id | record id | property | value >> >> Line IDs are unique and don't matter. All lines with the same record >> ID give a value to a property in the same record, similar to this: >> >> 1|1|name|arthur >> 2|1|quest|seek holy grail >> 3|1|colour|blue >> 4|2|name|robin >> 5|2|quest|run away >> 6|2|colour|yellow >> >> Organizing that was a joy. It took minutes: > > let cutUp = tail (filter (\fields -> (length fields) == 4) > (map (\x -> split x '\t') > (lines text))) > > This should almost certainly be a function of text: > > cutUp text = tail (filter (\fields -> (length fields) == 4) > (map (\x -> split x '\t') (lines > text))) > >> I found a split on someone's blog (looking for a library tokenizer), >> but I can understand it just fine. I even get to chuck out ill-formed >> lines and remove the very first (which contains MySql column names) >> on >> the way through! > > Sadly, there's no general library function for doing this. We have > words and lines (and words would work here, if your fields never have > spaces), but nobody's bothered to put anything more general for simple > splitting into the base libraries (though I'm sure there's plenty on > hackage -- MissingH has a Data.String.Utils module which contains > split and a bunch of others, for example). However, for anything more > complicated, there are also libraries like Parsec, which are generally > really effective, so I highly recommend looking at that at some point. > >> I then made a record to put things in, and wrote some lines to play >> with it (these are the real property names): >> >> data Entry = Entry >> { occupation :: String >> , iEnjoyMyJob :: Int >> , myJobIsWellDefined :: Int >> , myCoworkersAreCooperative :: Int >> , myWorkplaceIsStressful :: Int >> , myJobIsStressful :: Int >> , moraleIsGoodWhereIWork :: Int >> , iGetFrustratedAtWork :: Int >> } >> ... >> let e = Entry{occupation = "", iEnjoyMyJob = 0} >> let f = e {occupation = "alan"} >> let g = f {iEnjoyMyJob = 47} >> putStrLn ((occupation g) ++ " " ++ (show (iEnjoyMyJob g))) >> >> Then I ran into another quagmire. I think I have to use Data.Map to >> build a collection of records keyed by record id, and fill them in by >> working through the list of 4 item lists called cutUp. As with the >> file opening problem I can find a few examples that convert a list of >> tuples to a Data.Map, one to one. I found a very complex example that >> convinced me a map from Int to a record is possible, but gave me no >> understanding of how to do it. I spent a while trying to use foldl >> before I decided it can't be appropriate (I need to pass more >> values). >> So I tried a couple of recursive functions, something like: >> >> type Entries = M.Map Int Entry >> ... >> let entries = loadEntries cutUp >> ... >> loadEntries :: [[String]] -> Entries >> loadEntries [] = M.empty Entries >> loadEntries [x : xs] = loadEntry (loadEntries xs) x > -- Possible common beginner error here: [x:xs] means the list with one > element which is a list whose first element is x and whose tail is xs. > Your type signature and the type of cutUp seems to confirm that this > is the right type, but you don't seem to have a case to handle a > longer list of lists. If you want just a list with first entry x, and > with tail xs, that's just (x:xs). If you want to handle lists of lists > recursively, you'll generally need two cases: ([]:xss) and > ((x:xs):xss). We'll end up doing something different instead of > recursion in a moment. >> >> loadEntry entries _ rid fld val = entries >> >> Trying to create an empty map at the bottom of the recursion so later >> I can try to fiddle about checking if the key is present and >> crating a >> new record otherwise, then updating the record with a changed one (a >> big case would be needed deep in to do each property update). If I'm >> on the right track it's not good enough to get better, so now I'm >> just >> throwing bits of forest animals into the pot at random again :-( >> >> So I certainly would be grateful for a clue! The bits I can do (I got >> a non-trivial wxHaskell frame sorted out quite easily, the tokenizing >> and record bit were OK) I think show I'm not *totally* stupid at >> this, >> I'm putting loads of time investment in (it's an experiement in >> itself) but there do seem to be certain specific things that would be >> ubiquitous patterns in any production or scripting environment, which >> are not discussed at all and far from obvious. The more I see of >> Haskell the more I suspect this issue is the gating one for popular >> uptake. >> >> I couldn't help thinking of this bit, from the Wikipedia entry on the >> Cocteau Twins: >> >> "The band's seventh LP, Four-Calendar Café, was released in late >> 1993. >> It was a departure from the heavily-processed, complex and layered >> sounds of Blue Bell Knoll and Heaven or Las Vegas, featuring clearer >> and more minimalistic arrangements. This, along with the record's >> unusually comprehensible lyrics, led to mixed reviews for the album: >> Some critics accused the group of selling out and producing an >> 'accessible album,' while others praised the new direction as a >> felicitous development worthy of comparison with Heaven or Las >> Vegas." >> >> Best wishes, >> >> Alan > > I woke up rather early, and haven't much to do, so I'll turn this into > a tutorial. :) > > Okay. The most common ways to build a map are by using the fromList, > fromListWith, or fromListWithKey functions. You can see them in the > documentation here: > > http://www.haskell.org/ghc/docs/latest/html/libraries/containers/Data-Map.html#v%3AfromList > > The types are: > > fromList :: (Ord k) => [(k,a)] -> Map k a > > fromListWith :: (Ord k) => (a -> a -> a) -> [(k,a)] -> Map k a > > fromListWithKey :: (Ord k) => (k -> a -> a -> a) -> [(k,a)] -> Map k a > > They take a list of (key,value) pairs, and build a map from it. > Additionally, the fromListWith function takes a function which > specifies how the values should be combined if their keys collide. > There is also a fromListWithKey function which allows the means of > combination to depend on the key as well. > > At this point we realise something interesting about the way the data > is being represented: if there is a field in someone's record with no > row in the database, what should the resulting field contain? In C, > they often use some integer which is out of range, like -1 for this. > > How about for a missing occupation field? Well, that's a String, you > could use some generic failure string, or an empty string, but I'll > show you another possibility that just might be convenient. > > If t is any type, then the type (Maybe t) consists of the values > Nothing, and Just x, whenever x is a value of type t. This is another > convenient way to represent the idea that a computation might fail. > > Let's start by changing your record type so that each field is a Maybe > value, that is, either the value Nothing, or the value Just x, where x > is the value it would have been. > > data Entry = Entry > { occupation :: Maybe String > , iEnjoyMyJob :: Maybe Int > , myJobIsWellDefined :: Maybe Int > , myCoworkersAreCooperative :: Maybe Int > , myWorkplaceIsStressful :: Maybe Int > , myJobIsStressful :: Maybe Int > , moraleIsGoodWhereIWork :: Maybe Int > , iGetFrustratedAtWork :: Maybe Int > } > > There's a very general function in the module Control.Monad which I'd > like to use just for the Maybe type here. It's called mplus, and for > Maybe, it works like this: > > mplus (Just x) _ = Just x > mplus Nothing y = y > > So if the first parameter isn't Nothing, that's what you get, > otherwise, you get the second parameter. Of course, this operation has > an identity element which is Nothing. > > So this lets you combine partial information expressed by Maybe types, > in a left-biased way. > > It's about to become obvious that record types are less convenient > than perhaps they could be in Haskell, and this is absolutely true -- > I'd actually probably use a somewhat different representation myself > (possibly something involving a Map from Strings (field names) to Int > values), but I can't really be sure what you intend with this data, > and how much type safety you want. > > I'll elide the field names just because I can here. It's not > necessarily good style. > > combine :: Entry -> Entry -> Entry > combine (Entry a1 a2 a3 a4 a5 a6 a7 a8) (Entry b1 b2 b3 b4 b5 b6 b7 > b8) > = Entry (a1 `mplus` b1) (a2 `mplus` b2) (a3 `mplus` b3) (a4 > `mplus` b4) > (a5 `mplus` b5) (a6 `mplus` b6) (a7 `mplus` b7) (a8 > `mplus` b8) > > Even with all the shorthand, this is pretty ugly (and I'll show how > I'd represent the data in a moment), but what this does is to combine > two partial entries, favouring the information in the > first, but filling the holes in the first with data from the second. > This operation has an identity element, which is: > > emptyEntry = Entry Nothing Nothing Nothing Nothing Nothing Nothing > Nothing Nothing > > Let's try a different representation, which is a little more flexible, > but expresses less in the type system. > > data Entry = Entry { occupation :: Maybe String, survey :: M.Map > String Int } > deriving (Eq, Ord, Show) > > So now, instead of a bunch of separate Maybe Int fields, we have just > one Map from String to Int. If we don't have information for a field, > we simply won't have that key in the Map. Of course, this means we'll > have to use strings for field labels. If that seems unhappy, you could > always define a type like: > > data SurveyQuestion = IEnjoyMyJob > | MyJobIsWellDefined > | MyCoworkersAreCooperative > | MyWorkplaceIsStressful > | MyJobIsStressful > | MoraleIsGoodWhereIWork > | IGetFrustratedAtWork > deriving (Eq, Ord, Show) > > to be used in place of the String type. > > Let's see how combine will look now: > > combine :: Entry -> Entry -> Entry > combine (Entry o1 s1) (Entry o2 s2) = Entry (o1 `mplus` o2) (s1 > `M.union` s2) > > Or, using the record syntax more: > > combine :: Entry -> Entry -> Entry > combine e1 e2 = Entry { occupation = (occupation e1 `mplus` > occupation e2), > survey = (survey e1 `M.union` survey e2) } > > Again, this new version has an identity with respect to combine, > which is: > > emptyEntry = Entry {occupation = Nothing, survey = (M.empty)} > > Now, we just need a way to take one of your rows, and turn it into a > (key,value) pair, where the value is a partial entry. > > readRow :: [String] -> (Int, Entry) > readRow [n, k, "occupation", v] = (read k, emptyEntry { occupation = > Just v }) > readRow [n, k, f, v] = (read k, emptyEntry { survey = M.singleton f > (read v) }) > readRow xs = error "failure case, should never happen!" > > There is actually a failure case that I'm not handling here, which is > what happens when the value or key fails to parse as an Int. For that > we'd use reads instead of read, but let's ignore it for now. > > We can then map this function over our cut up rows, something along > the lines of: > > map readRow (cutUp text) > > at which point we'll have a list of (Int, Entry) pairs. > > We then want to fill up our Entries Map with those, and we want to > combine them as we go using the combine function: > > entryMap text = M.fromListWith combine (map readRow (cutUp text)) > > Some final changes we could consider would be putting more of the > error handling into readRow itself: if it was to return a singleton > Map rather than an (Int, Entry) pair, then it could return the empty > Map on failure, and the results would then be combined using the > function M.unionsWith combine. We could move the length 4 test out of > cutUp then, and just make it the fall-through case in readRow. I'll > also use reads, which returns a list of (parse,rest-of-string) pairs, > to handle the failure cases where the numbers don't parse, by just > treating those rows as nonexistent: > > readRow :: [String] -> M.Map Int Entry > readRow [n, k, f, v] = > case reads k of > [] -> M.empty -- the key didn't parse > (k',_):_ -> > if f == "occupation" > then M.singleton k' (emptyEntry { occupation = Just v }) > else case reads v of > [] -> M.empty -- the value didn't parse > (v',_):_ -> M.singleton k' > (emptyEntry { survey = > M.singleton f v' }) > readRow xs = M.empty -- this handles the case when the list is any > length but 4 > > cutUp text = tail (map (\x -> split x '\t') (lines text)) -- which > allows cutUp to be simpler > > entryMap text = M.unionsWith combine (map readRow (cutUp text)) > > Anyway, I hope this tutorial gives some idea of how things progress, > and what sort of thinking is generally involved. Note that the focus > here was more on finding the right combining operations, and then > using pre-existing higher-order functions to collapse the structure, > than it was on recursion. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellMany thanks for the explanations when I was first experimenting with
Haskell. I managed to finish translating a C++ wxWidgets program into Haskell wxHaskell, and am certainly impressed. I've written up some reflections on my newbie experience together with both versions, which might be helpful to people interested in popularizing Haskell, at: http://the-programmers-stone.com/2008/03/04/a-first-haskell-experience/ Regards, Alan -- ... the PA system was moaning unctuously, like a lady hippopotamus reading A. E. Housman ..." -- James Blish, "They Shall Have Stars" _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellAlan Carter wrote:
> I've written up some reflections on my newbie experience together with > both versions, which might be helpful to people interested in > popularizing Haskell, at: > > http://the-programmers-stone.com/2008/03/04/a-first-haskell-experience/ > Thank you for writing this. On the lack of simple examples showing, for example, file IO: I seem to recall a Perl book (maybe it was Edition 1 of the Camel Book) which had lots of very short programs each illustrating one typical job. Also the Wiki does have some pages of "worked example" programs. But I agree, we could do better. I'm surprised you found the significant whitespace difficult. Yes, the formal rules are a bit arcane, but I just read them as "does the Right Thing", and it generally works for me. I didn't know about the significance of comments, but then I've never written an outdented comment. I had a look through your code, and although I admit I haven't done the work, I'm sure that there would be ways of factoring out all the commonality and thereby reducing the length. Finally, thanks for that little story about the BBC B. I had one of those, and I always wondered about that heatsink, and the stonking big resistor next to it. They looked out of scale with the rest of the board. Paul. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellPaul Johnson <paul@...> writes:
> I'm surprised you found the significant whitespace difficult. I wonder if this has something to do with the editor one uses? I use Emacs, and just keep hitting TAB, cycling through possible alignments, until things align sensibly. I haven't really tried, but I can imagine lining things up manually would be more painful, especially if mixing tabs and spaces. -k -- If I haven't seen further, it is by standing in the footprints of giants _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellOn Tue, Mar 4, 2008 at 4:16 AM, Ketil Malde <ketil@...> wrote:
> Paul Johnson <paul@...> writes: > > > I'm surprised you found the significant whitespace difficult. > > I wonder if this has something to do with the editor one uses? I use > Emacs, and just keep hitting TAB, cycling through possible alignments, > until things align sensibly. I haven't really tried, but I can > imagine lining things up manually would be more painful, especially > if mixing tabs and spaces. Especially if mixing tabs and spaces indeed. Haskell does the Python thing of assuming that a tab is 8 spaces, which IMO is a mistake. The sensible thing to do if you have a whitespace-sensitive language that accepts both spaces in tabs is to make them incomparable to each other; i.e. main = do <sp><sp>putStrLn $ "Hello" <sp><sp><tab>++ "World" -- compiles fine main = do <sp><sp>putStrLn $ "Hello" <tab>++ "World" -- error, can't tell how indented '++ "World"' is... Luke _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
|
|
Re: Doubting HaskellOn 04/03/2008, Alan Carter <alangcarter@...> wrote:
> http://the-programmers-stone.com/2008/03/04/a-first-haskell-experience/ That was an interesting read. Thanks for posting it. I also liked the tale of the BBC ULA - it reminded me of a demo I saw once at an Acorn show, where they had a RISC PC on show, with a (IBM) PC card in it. They were demonstrating how hot the PC chip runs compared to the ARM RISC chip by using it to make toast. I dread to think what you could do with one of today's monsters :-) Paul. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@... http://www.haskell.org/mailman/listinfo/haskell-cafe |
| < Prev | 1 - 2 - 3 | Next > |
| Free embeddable forum powered by Nabble | Forum Help |