using haskell for a project

Hi, I don't think I already presented myself; I'm Nicolas, a 23y french student, trying to learn and use haskell. I've been using C for years, for all sort of tasks, and am quite comfortable with it. I'm also using it 40h a week in my internship for network systems, so I kind of know how to use it. I discovered Haskell some monthes ago, bought `Real World Haskell', quickly read, and enjoyed it. So now I'd want to use it for a small project of mine, a simple multiplayer roguelike based on telnet. I wrote a minimal server in C, and it took me a few hours. Now I'm thinking about doing the same in Haskell, and I'm in trouble. I don't really know how to map my ideas in haskell code. For example, a character can cast spells, so I'd have something like this in C: struct hashtable spells; struct character { int n_spells; struct spell **spells; }; I thought I could do something like this in haskell: spells = Data.Map.Map Int Spell data Character = Character { charSpells :: [Int] } But now I don't know how to dynamically add new spells (new spells can be created in my gameplay). Since I can't assign a new value to the `spells' variable (Data.Map.insert returns a new map), I just don't know where to go. I have the same problem for a bout every problem. I love writing pure functions in haskell, but as soon as I try to write some code involving states or side effects, I can't write a line. I just wanted a 2d array to store a zone, for example, dead simple in C, but this kind of link http://greenokapi.net/blog/2009/03/10/rough-grids-in-haskell make me shiver. Point is, I'd like to use haskell, but I don't know how, it seems totally alien. How did you manage to change the way you map ideas to code, from imperative to pure functional ? Thank you. Regards, -- Nicolas Martyanoff http://codemore.org khaelin@gmail.com

At 7:17 PM +0200 5/2/09, Nicolas Martyanoff wrote:
Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="ibTvN161/egqYuK8" Content-Disposition: inline
Hi,
I don't think I already presented myself; I'm Nicolas, a 23y french student, trying to learn and use haskell.
I've been using C for years, for all sort of tasks, and am quite comfortable with it. I'm also using it 40h a week in my internship for network systems, so I kind of know how to use it.
I discovered Haskell some monthes ago, bought `Real World Haskell', quickly read, and enjoyed it.
So now I'd want to use it for a small project of mine, a simple multiplayer roguelike based on telnet. I wrote a minimal server in C, and it took me a few hours. Now I'm thinking about doing the same in Haskell, and I'm in trouble.
I don't really know how to map my ideas in haskell code. For example, a character can cast spells, so I'd have something like this in C:
struct hashtable spells;
struct character { int n_spells; struct spell **spells; };
I thought I could do something like this in haskell:
spells = Data.Map.Map Int Spell
data Character = Character { charSpells :: [Int] }
But now I don't know how to dynamically add new spells (new spells can be created in my gameplay). Since I can't assign a new value to the `spells' variable (Data.Map.insert returns a new map), I just don't know where to go.
I have the same problem for a bout every problem. I love writing pure functions in haskell, but as soon as I try to write some code involving states or side effects, I can't write a line.
I just wanted a 2d array to store a zone, for example, dead simple in C, but this kind of link http://greenokapi.net/blog/2009/03/10/rough-grids-in-haskell make me shiver.
Point is, I'd like to use haskell, but I don't know how, it seems totally alien.
How did you manage to change the way you map ideas to code, from imperative to pure functional ?
Thank you.
Regards,
-- Nicolas Martyanoff http://codemore.org khaelin@gmail.com
Nicolas, First, bienvenue à Haskell ! Learning it will stretch your mind; it may be rocky at times, but it will be rewarding. You've quickly come upon a key difference between imperative and functional programming. State management in Haskell is more explicit, which is a double-edged sword. It requires greater discipline and mechanism, but provides greater control and security. In your example program you could manage your state with a State monad. Assuming you'll want to be able to do I/O, you'll probably want to combine State with IO. For starters, something like:
import Control.Monad.State import qualified Data.Map as M
data Spell = ... data Character = Character { charName :: String, charSpells :: [Spell], ... } data MyState = MyState { characters :: M.Map String Character, ... } initialState = MyState { characters = M.empty, ... }
type MyMonad = StateT MyState IO
addSpellForCharacter :: String -> Spell -> MyMonad () addSpellForCharacter name spell = do state <- get let chars = characters state case M.lookup name chars of Just char -> let char' = char { charSpells = spell : charSpells char } state' = state { characters = M.insert name char' chars } in put state' Nothing -> ... -- leave these issues for another time
main = do ... finalState <- execStateT game initialState ...
game :: MyMonad () game = do ... addSpellForCharacter ... liftIO $ putStrLn "Added spell ..." ...
Dean

On Sat, May 2, 2009 at 6:17 PM, Nicolas Martyanoff
Hi,
I don't think I already presented myself; I'm Nicolas, a 23y french student, trying to learn and use haskell.
I've been using C for years, for all sort of tasks, and am quite comfortable with it. I'm also using it 40h a week in my internship for network systems, so I kind of know how to use it.
I discovered Haskell some monthes ago, bought `Real World Haskell', quickly read, and enjoyed it.
So now I'd want to use it for a small project of mine, a simple multiplayer roguelike based on telnet. I wrote a minimal server in C, and it took me a few hours. Now I'm thinking about doing the same in Haskell, and I'm in trouble.
I don't really know how to map my ideas in haskell code. For example, a character can cast spells, so I'd have something like this in C:
struct hashtable spells;
struct character { int n_spells; struct spell **spells; };
I thought I could do something like this in haskell:
spells = Data.Map.Map Int Spell
data Character = Character { charSpells :: [Int] }
But now I don't know how to dynamically add new spells (new spells can be created in my gameplay). Since I can't assign a new value to the `spells' variable (Data.Map.insert returns a new map), I just don't know where to go.
I'm not sure I understand how your C version and Haskell version are similar? Wouldn't the character just have a list of Spells (since this is what the C version seems to do)? That global spells variable should probably be put in some sort of "game state" data type that encapsulates the game world. Then consider writing updates as a function that takes the old value, and produces a new value. Indeed, consider letting the following function be your main "update" for the game state. gameTick :: Time -> PlayerInput -> GameState -> GameState That function would update all parts of your game state, and if you want to change some property of a character, you simply compute a new character from the old one with the field you want to change updated. Because values are immutable, any data you don't touch will just refer to the old stuff so it's actually quite efficient. You main loop could then be something like: gameLoop oldTime gameState = do time <- getTime let dt = time - oldTime input <- processInput gameState gsNew <- gameTick dt input gameState renderGame gsNew gameLoop time gsNew
I just wanted a 2d array to store a zone, for example, dead simple in C, but this kind of link http://greenokapi.net/blog/2009/03/10/rough-grids-in-haskell make me shiver.
Try a list of lists, or better yet just an Array. Make sure you update the grid "in bulk" though, as modifying just a single element at a time is slow with immutable arrays.
Point is, I'd like to use haskell, but I don't know how, it seems totally alien.
How did you manage to change the way you map ideas to code, from imperative to pure functional ?
Massive brain-rewiring. Keep at it, don't think in terms of modifying state, think of it as computing new values from old values. I find that the payoff of learning to think ,like this is massive, as it's usually much easier to reason about. If you really do lots of "state" in a program, consider using a state monad like someone else already mentioned, but honestly I'd try to stay away from it and stick to a more "functional" style as far as possible. -- Sebastian Sylvan +44(0)7857-300802 UIN: 44640862

don't think in terms of modifying state, think of it as computing new values from old values. I find that the payoff of learning to think ,like this is massive, as it's usually much easier to reason about. </qoute> Indeed. [warning: what follows is a rant with a purpose:] The imperative/OO guys have learnt this as well, and the result comes under different names, e.g., "a service component should be stateless", "stateless session bean", "refactoring: introduce state object". It's kind of funny how they re-invent functional programming (in several places, e.g. "composite pattern" = algebraic data type, "visitor pattern" = fold, "iterator pattern" = lazy list). ... after trying to avoid the truth for some 20 years or so. You're exactly right, the functional/declarative way is "much easier to reason about", and this matches the observation that there was not much reasoning going on during these decades instead, just hacking, and then some testing. Well, they even finally admitted one should write the tests before coding. Yes, that's called specification before implementation, and that's what Dijkstra had been teaching for ages, e.g., http://www.cs.utexas.edu/users/EWD/transcriptions/EWD13xx/EWD1305.html Still, given their strange approach to programming, the imperative/OO guys have rather brilliant tools for developers. No surprise, without them they'd be lost immediately. But we have http://leksah.org/ , and there's a GSoC project for eclipsefp . [now, the punchline:] (for extended rants on the subject, register for http://www.iba-cg.de/hal4.html ) -- View this message in context: http://www.nabble.com/using-haskell-for-a-project-tp23348425p23353526.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Welcome to Haskell! =)
But now I don't know how to dynamically add new spells (new spells can be created in my gameplay). Since I can't assign a new value to the `spells' variable (Data.Map.insert returns a new map), I just don't know where to go.
Do distinguish *pure function* concept and *action with side effects* concept. The default in FP (Funct. Progr.) paradigm usualy is *pure function*, if *action with side effects* is avoidable. Pure functions deal with immutable memory "objects". So in your case, whenever you add a new spell, you get a new character (since your chacter's "essence" is a spell list). That way after calculating *addNewSpell* you will have 2 versions of character: a new one (with spells list bigger), an the original one. Since old one usualy drop out of the scope (while program evaluation progresses) it gets *garbage collected* (note: garbage collection showed up in FP already in 1960s). addNewSpell :: Character -> Spell -> Character addNewSpell char_old_version spell_to_add = ... main = let char_new_version = addNewSpell char_old_version new_spell in putStrLn $ show char_new_version where char_old_version = Charcter {...} new_spell = Spell { .... } Have luck, with the brain rewriting! =) Belka -- View this message in context: http://www.nabble.com/using-haskell-for-a-project-tp23348425p23352598.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

To the original author: I must notice that this is not the most
convincing use of purity. I personally would prefer to have a
character's spell list be mutable because this corresponds better to
the nature of the problem (in the problem domain it is nonsense to
have two versions of a character and hope that one version will drop
out of the scope).
However, Haskell forces you to be pure, and that pays off a lot,
despite the existence of problems that are not modeled intuitively
this way.
In case you absolutely need mutable state, use the ST monad or
IORef's, but **you have to first become skilled with pure
computations, because that's the only way to not make a mess of your
treatment of the impure ones**.
And if anyone tries to seduce you with unsafePerformIO, resist!
2009/5/3 Belka
Welcome to Haskell! =)
But now I don't know how to dynamically add new spells (new spells can be created in my gameplay). Since I can't assign a new value to the `spells' variable (Data.Map.insert returns a new map), I just don't know where to go.
Do distinguish *pure function* concept and *action with side effects* concept. The default in FP (Funct. Progr.) paradigm usualy is *pure function*, if *action with side effects* is avoidable. Pure functions deal with immutable memory "objects". So in your case, whenever you add a new spell, you get a new character (since your chacter's "essence" is a spell list). That way after calculating *addNewSpell* you will have 2 versions of character: a new one (with spells list bigger), an the original one. Since old one usualy drop out of the scope (while program evaluation progresses) it gets *garbage collected* (note: garbage collection showed up in FP already in 1960s).
addNewSpell :: Character -> Spell -> Character addNewSpell char_old_version spell_to_add = ...
main = let char_new_version = addNewSpell char_old_version new_spell in putStrLn $ show char_new_version where char_old_version = Charcter {...} new_spell = Spell { .... }
Have luck, with the brain rewriting! =) Belka -- View this message in context: http://www.nabble.com/using-haskell-for-a-project-tp23348425p23352598.html Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Eugene Kirpichov Web IR developer, market.yandex.ru

Hi Nicolas, Nicolas Martyanoff wrote:
So now I'd want to use it for a small project of mine, a simple multiplayer roguelike based on telnet. I wrote a minimal server in C, and it took me a few hours. Now I'm thinking about doing the same in Haskell, and I'm in trouble.
I don't know if this is of any help at all but I've been working a bit on a MUD in Haskell. You can find the source code here: http://code.google.com/p/custard/ You might be able to get some ideas from the source code. If you have any questions, feel free to ask. There are no spells (yet), but there are players and rooms and you can walk around a few rooms. Martijn.

Hello Nicolas, Saturday, May 2, 2009, 9:17:55 PM, you wrote:
But now I don't know how to dynamically add new spells (new spells can be created in my gameplay). Since I can't assign a new value to the `spells' variable (Data.Map.insert returns a new map), I just don't know where to go.
well, i've written mid-size program that combines pure haskell, imperative haskell and c++ and that's my vision: in C, you don't have the barrier between pure and imperative worlds and as result you don't got habit to distinguish them. haskell forces you to separate pure and imperative code: pure code is much simpler to write but it cannot call imperative one (i.e. function can't call procedures) so you should understand the difference and carefully make your choice you are *forced* to use imperative code when it responds to some external events - user input, network input, so on. so when your spell list mutates as a result of external events, you should do something imperatively. although it may be as easy as tail-recursively calling itself with purely modified value: mainCycle spells = do x <- userInput case x of AddSpell -> mainCycle (newSpell:spells) .... further improving this idea, you may develop data structire contating whole state info: data GameState = GameState {spells: [Spell], .....} and update appropriate parts of GameState on tail-recursive calls: mainCycle gameState = do x <- userInput case x of AddSpell -> mainCycle (gameState {spells = newSpell:spells gameState}) .... as you see, this approach allows you to live in imperative world but use only pure computations to update state but once your program will become larger, you may find that this approach needs too much typing. in that case, you can program using IORefs, MVars and other types of C-like global vars. or, you may use them semi-globally - i.e. create this vars in outside procedure and then pass to all interested routines: main = do vspells <- newIORef [] let stateVars = StateVars {spells=vspells, ...} mainCycle stateVars you may even use implicit parameters to hide passing details from program code but i don't have experience of using them -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com
participants (8)
-
Belka
-
Bulat Ziganshin
-
Dean Herington
-
Eugene Kirpichov
-
j.waldmann
-
Martijn van Steenbergen
-
Nicolas Martyanoff
-
Sebastian Sylvan