In my previous post I wrote about a, probably rather naïve, approach to constructing state machines in Haskell. I ended it with a saying that the pattern matching of Haskell makes it rather simple to manually write the step function required to create a working state machines. Hopefully this post can convince you I’m right.
The vehicle I’ve chosen is a very simple machine capable of reading two integers and adding them. In slightly more detail it’s a machine that:
- reads a total of three parts, two integers followed by a plus sign (+)
- each part is separated by whitespace
- on errors the machine resets and starts over
The signals (a.k.a. the output alphabet) is the following typedata CalcSignal = CalcNothing | CalcResult Int | CalcError CalcStates String deriving (Eq, Show)
The events (a.k.a. the input alphabet) is simply Char. The states aredata CalcStates = Start | ReadFirst Int | ReadSecond Int Int | ReadOperator Int Int deriving (Eq, Show)
where the names hopefully are self explanatory. The type of the machine is thentype CalcMachine = Machine CalcStates Char CalcSignal
The machine itself can then be written like this:calcMachine :: CalcMachine calcMachine = createMachine Start go where go Start e | isNumber e = (ReadFirst (read [e]), CalcNothing) | otherwise = (Start, CalcError Start "No number") go s@(ReadFirst i) e | isNumber e = (ReadFirst (10 * i + read [e]), CalcNothing) | isSpace e = (ReadSecond i 0, CalcNothing) | otherwise = (Start, CalcError s "Bad format") go s@(ReadSecond l i) e | isNumber e = (ReadSecond l (10 * i + read [e]), CalcNothing) | isSpace e = (ReadOperator l i, CalcNothing) | otherwise = (Start, CalcError s "Bad format") go s@(ReadOperator i j) e | e == '+' = (Start, CalcResult (i + j)) | isSpace e = (s, CalcNothing) | otherwise = (Start, CalcError s "Bad operator")
That’s rather simple and easy to read I find. Though I’m not sure it scales too well to much larger machines. I’ve not really used any DSLs to create large machines either, so I don’t know how well any method scales ;)
To do a bit of exploratory testing it’s handy to create the following functioncalculate :: String -> IO () calculate = foldM_ go calcMachine where go mach c = do let (m, s) = stepMachine mach c print s return m
Using that function it’s easy to check if the machine works as intended.> calculate "56 67 +" CalcNothing CalcNothing CalcNothing CalcNothing CalcNothing CalcNothing CalcResult 123
So far so good. What about the behaviour on errors?> calculate "5a6 67 +" CalcNothing CalcError (ReadFirst 5) "Bad format" CalcNothing CalcNothing CalcNothing CalcNothing CalcNothing CalcResult 73
That looks good enough to me. Though there is (at least) one detail of how the machine works that might be surprising and hence should be fixed, but I’ll leave that as an exercise for the reader ;)
As I mentioned in the previous post I’ve been using this method for writing state machines to implement two different protocols. For the IO I used conduit which means I had to turn the state machine into a conduit. I’ll write about that in a later post though.
We recently released version 3.2 of FP Haskell Center. We want to take this opportunity to list some of the new features and highlight the additions of a Hosted Haddocks button and the ability to set up personal RSS feeds within each account.3.2 Features List
- Support for downloading extra packages from arbitrary.tar and .gz urls (available from the “extra packages” tab of the settings page)
- Auto-insert functionality works for error messages (used to only work for warnings)
- Toggle executable bit in UI. You can now make data files executable inside the IDE.
- Updated hlint version for better functionality
- Hosted Haddock button
- Per-user RSS feed /user-feed/username to access
Often times when you’re working on a codebase, it’s convenient to generate the Haddocks to get an idea of what’s going on. It’s also useful to be able to share those generated Haddocks with others. FP Haskell Center now allows you to do both with a single click. Inside the deployment menu, you can now generated Haddocks for your current project. Links to dependencies will be created correctly, and the generated URL is fully shareable with others.Per-user RSS Feed
Users now have the ability to set up personal RSS Feeds within their accounts. This answers a request from some users to be able to more easily let people stay up-to-date with their content. This ties in nicely with our previous addition of Disqus comments.Feedback is always appreciated
We are proud of every improvement we make to FP Haskell Center and look forward to your feedback. With each release we are continuing to raise the quality of our product.
Why does the default cabal package file have a build-depends of base >= 4.7 && base < 4.8? Why not just base?
It occurs to me that a project should always use the latest base package. So why limit it to 4.7.x?submitted by stasiana
[link] [12 comments]
This Senior Software Engineer position is with the new LearnSmart team at McGraw-Hill Education's new and growing Research & Development center in Boston's Innovation District.
We make software that helps college students study smarter, earn better grades, and retain more knowledge.
The LearnSmart adaptive engine powers the products in our LearnSmart Advantage suite — LearnSmart, SmartBook, LearnSmart Achieve, LearnSmart Prep, and LearnSmart Labs. These products provide a personalized learning path that continuously adapts course content based on a student’s current knowledge and confidence level.
On our team, you'll get to:
- Move textbooks and learning into the digital era
- Create software used by millions of students
- Advance the state of the art in adaptive learning technology
- Make a real difference in education
If you're interested in functional languages like Scala, Swift, Erlang, Clojure, F#, Lisp, Haskell, and OCaml, then you'll enjoy learning Flow. We don't require that you have previous experience with functional programming, only enthusiasm for learning it. But if you have do some experience with functional languages, so much the better! (On-the-job experience is best, but coursework, personal projects, and open-source contributions count too.)
We require only that you:
- Have a solid grasp of CS fundamentals (languages, algorithms, and data structures)
- Be comfortable moving between multiple programming languages
- Be comfortable with modern software practices: version control (Git), test-driven development, continuous integration, Agile
Get information on how to apply for this position.
Using Exceptions as a general error handling strategy within an acid-state update/query won't work, read the point about stateNestedError1 here.
Until now I have been using the following pattern for error handling:type MyUpdate st e a = StateT st (Either e) a runMyUpdate :: MyUpdate st e a -> Update st (Either e a) runMyUpdate act = do s <- get case runStateT act s of Left e -> return $ Left e Right (x,s') -> do put s' return $ Right x setVal' :: Int -> MyUpdate Int String () setVal' 5 = throwError "wrong number" setVal' x = put x setVal :: Int -> Update Int (Either String ()) setVal = runMyUpdate . setVal' makeAcidic ''Int ['setVal]
But I realize that this will still write the failing update to the event log, so you will have a lot of transactions in the log that don't modify the state. An alternative would be for runMyUpdate to throw an Exception instead (this will be ok since the exception is not nested).
What error handling strategies are other acid-state users using?submitted by ttfh
[link] [5 comments]
- December 30th, 2014: Why can't we all just consensus along? for today's Haskell problem lpaste.net/117487 Pro-, con-, anti-, ... it's all sensus to me! lpaste.net/117490
- December 29th, 2014: Uh, wait! What? It's another day? We need another #haskell puzzler? Here ya go! Rosalind subs (not grinders) http://lpaste.net/117421 Rose petals falling ... and a soution to the #rosalind subs problem http://lpaste.net/117481
- December 24th, 2014: A||B||C == Merry Christmas for today's haskell problem http://lpaste.net/117213
- December 23rd, 2014: Convergence, but not the movie, is today's #haskell problem http://lpaste.net/117089 A rational solution was posted by @sheshanaag at http://lpaste.net/117232
- December 22rd, 2014: Yesterday was about the zeroes, today's haskell problem is about the squares http://lpaste.net/116990
- December 21nd, 2014: In which we want to have the most zeros. Fancy that! http://lpaste.net/116932 (I guess we're not playing Dodgeball, then!)
- December 19th, 2014: A question for today's #haskell problem: how do YOUclear a Writer monad's log? http://lpaste.net/116849 A FlushableWriter solutionwas posted by @aditcr8 at http://lpaste.net/117115
- December 18th, 2014: Why can't you spell 'PROTEIN' with proteins?lpaste.net/116723 The solution for this problem is to Eat your proteins, young man! lpaste.net/116808
- December 17th, 2014: In which we find out that Mendel was into the Domme-scene for today's #haskell problem http://lpaste.net/116683 Whether hetero- or homo- a zygous is still a zygous... whatever that is. A solution to today's #haskell-zygous problem is posted at http://lpaste.net/116711
- December 16th, 2014: All actors should relate to today's #haskell problem; it's all about H-A-M-M! http://lpaste.net/116578 Go HAMM it up; #Rosalind will love you. And the solution is so HAMMy! http://lpaste.net/116585
- December 15th, 2014: Wanna Date? In which Jane Austen writes today's #haskell problem in her modern book titled: "The Hook Up" http://lpaste.net/116486 aka Pride and Prejudice. To get to our solution space, first we have to write an l-expr scanner/parser, of course. http://lpaste.net/116558
- December 12th, 2014: In this case 'GC' does NOT mean 'garbage collection' for today's #rosalind #haskell problem lpaste.net/116305. Yeah, not garbage-collected, but a solution, nonetheless http://lpaste.net/116335
- December 11th, 2014: Why ... you ... wascally wabbit! Today's #haskell problem has a solution multiplying like Fibonaccis! http://lpaste.net/116216 I mean: rabbits. And speaking of rabid rabbits http://lpaste.net/116303, the solution is there. BLARGH!
- December 10th, 2014: "Hello, Strand, you're looking lovely in that dress!" Complimenting DNA for today's #haskell problem. http://lpaste.net/116147 No, wait: 'comPLEmenting' a strand of DNA. Sorry, Miss Rosalind! A nicely complimented solution to the DNA-complement problem posted at http://lpaste.net/116151
- December 9th, 2014: I think this is my week with dear Rosalind: DNA-to-RNA transcriber for today's #haskell problem http://lpaste.net/116068 Another #TweetedHaskellSolution posted to http://lpaste.net/116071 for today's DNA-to-RNA transcriber
- December 8th, 2014: Rosalind, dear Rosalie, wherefore art thou givest me bioinformatic puzzles to solve, counting nucleotides? http://lpaste.net/115961 #haskell Nucleotide-counter, HO! A nucleotide-counting solution is posted at http://lpaste.net/116011
- December 5th, 2014: This visit to Liar's-berg (or is it Truth-town?) we encounter only two women, so this should be 2x as easy to solve http://lpaste.net/114437 By coercion, we find that we are in Liarsberg, after all: http://lpaste.net/115769
- December 4th, 2014: Gadzooks! It's (past) that time of day again for the daily #haskell problem. Here: eat some glow worms! http://lpaste.net/114435
- December 3rd, 2014: Substantive citizens (with some substantive hints, for a change) for today's #haskell problem http://lpaste.net/114438
- December 2nd, 2014: There are some curious fractions to find fromprojecteuler.net for today's #haskell problem at http://lpaste.net/114208 Asolution to this curious fraction problem is posted at lpaste.net/114209
- December 1st, 2014: Today's Haskell problem is all about lambda-terms. It has NOTHING to do with for-loops and if-statements, ... NOT ONE BIT http://lpaste.net/115420 Solution: lpaste.net/115452