My last Haskell post had me thinking that I might as well create a really bad tutorial outlining my own strategies to deal with Haskell in the real world. Some of the issues I outlined were:
- Tutorials for Haskell focussed on solving problems, rather than getting it to ‘do stuff’ which is what alot of users expect from their computer software.
- Haskell is emerging as an important player in the future of code. Both as a type of code itself and as a way of improving skills in such languages as Java and Python. However, it will not make the mainstream unless ‘regular folk’ start using it.
- Functional programs (in theory) are apt to be more sustainable, less buggy and more consistently documented. Regular folk, working with imperative and/or objective and pseudo objective languages probably don’t realize this -> not until their code breaks and they have to re-install the wheel.
While I have some experience in other languages like Ruby, and Python, I’ve decided to approach Haskell as if I were a PHP developer instead. There are some very good reasons for this:
- PHP is a ‘do something’ language. Basically, it takes dynamic data and outputs it to a web page. While math problems and recursion-like methods are possible – it’s usually input and output (ie. taking data in and out of a MySQL database) that is the most important. Anyone expecting to use Haskell for primarily I/O related stuff is going to die from frustration.
- PHP code can get very messy, even in the hands of an experienced coder. Documentation of code is all dependent on comments and external manuals. Haskell can help your average PHP coder, because its type-system offers a kind of in-source documentation.
- PHP is a ‘regular peoples’ code. It is adopted by alot of people with varying skills and experience with computer software, many of whom have very little understanding of its long run limitations.
- Well into its 5th release, alot of the work has already been done for your average PHP coder. It’s almost not even necessary to create your own objects and functions with all the pre-created libraries available. Unfortunately, it’s also widely assumed that you are going to create a web application -> what if you want to turn your code into an App? or a desktop application that uses data from a php created api? or an intense web universe ala Second Life or World of WarCraft?
- As an interpreted program, it’s pretty simple to solve problems through trial and error. Just keep hacking away at php, and eventually you can make some convoluted function do what you want it to do (in an unscalable way, of course).
I am also going to make a number of assumptions:
- That you have read through at least some of the Haskell Wikibook. I do not intend to explain what a Monad is, or impress everyone with my knowledge of complex mathematical theory. This tutorial is an inquiry about how to approach a Haskell applications, not learning Haskell itself.
- You have a fair knowledge of some imperative-style computer language (possibly PHP).
As suggested, I am going to look at developing a one-level ‘rogue-like’ RPG game. If I were to start such a game in php, I might start with something like:
$playerChar = array ("name" => 'Bob', "class" => 'fighter', "STR" => '18', "DEX" => '14', "WIS" => '11', "INT" => '15');
I suggest this because PHP coders want to get to the action as fast as possible. The PHP coder (let’s call her PHiP) will know that her first problem is making data output in some consistent manner, so will create a variable that mimics a possible set of data that will eventually be displayed to the screen (likely a webpage). Knowing that things like the name and class of the character will change, PHiP will put some variables inside the array. Then PHiP will include some other ideas about what a character will need, and a print_r statement to watch the action as she lashes out blindly for the right outputs:
$playerChar ['traits'] = ("name" => $name, "class" => $class ...); $playerChar ['equip'] = ("weapon" => $weapon, "armour" => $armour ...); print_r ($playerChar);
If you are a Haskell coder, you probably already see countless disasters in store for PHiP if she uses this approach with Haskell. Here are a few:
- variables in Haskell are always constant. Once called, the values will not change. Believe it or not, functional programmers will see this as a good thing (see side effects in Wikipedia).
- playerChar [‘traits’] would be seen as a function with an input [‘traits’] that, using Haskell syntax, is a list containing one string value ‘traits’. Haskell would be wondering what to do if it encountered other lists containing one or more other string value(s).
- All of the variables inside the associative array $playerChar are irrelevant in Haskell. Unless they are constant.
- Deciding what to do with the array would be overwhelming. A list could be used, but would require that all values inside be strings. Or it could be a huge tuple of various kinds of values, or a list of tuples.
- Without being sure what types of values are needed to create the playerChar, there are almost sure to be problems letting PHiP’s player character switch its weapon from a sword to a mace and back.
In short, PHiP is using the wrong paradigm to code effectively in Haskell. The issue is not a problem of syntax, or even understanding a problem. The issue is the approach.
As the tutorial goes along, we will deal with PHiP’s player character. But, to work in Haskell, I propose that you do not start with the data you want to put in and out. Instead, you start with input and output itself – inside main – like this:
main :: IO() main = do x <- getChar if x == 'q' then putStrLn "Thanks for Playing" else pmove x >> main move :: Char -> String move a | a == 'w' = "UP!" | a == 's' = "DOWN!" | a == 'a' = "LEFT!" | a == 'd' = "RIGHT!" | otherwise = "HANG AROUND AND DO NOTHING!" pmove = print . move
Right now, this code is pretty useless, but it offers a few nice things to help make sure you don’t lose steam in your coding.
- It creates an output that will work (sort of) like PHiP’s print_r string.
- It offers a practical demonstration of point notation, which, in laymen’s terms creates a function pmove that prints (using print) the results of move. Essentially, it keeps me from having to write “print (move x)” all the time.
- I accepts an input ‘a’ that is a character.
- It creates a strongly typed function ‘move’ that takes a Character and returns a String. As we move forward, we can chain a series of functions together that will help PHiPs make her Haskell program to do more interesting things such as fight a monster.
(as it turns out, this code works slightly differently in Windows than it does in Linux. Use the Linux version, because it makes me seem a little more competent. If anyone can explain why Windows wants the CR for the getChar command, please add it to the comments.)
I am not absolutely sure this is the very best approach to a rogue-like game, but I can guarantee it is better to start this way than it is to begin with creating variables. As you read this tutorial, I hope you continue to use other documentations elsewhere to help you get your mind around my use of ‘do’, ‘getChar’, ‘putStrLn’ and guards ‘|’ here (pretty rudimentary Haskell code right now).
The next tutorial will look at shaping our dungeon and establishing where our player as he or she moves across the board.
Incidentally, as of writing this, I am working on a rogue-like game with my son called Rasghiosse (my son named it). I have a public Darcs repository on Patch-Tag that you are free to join in on if you like. As of writing this tutorial, I am not much further ahead than the above code, so I would appreciate your help.