
--- On Thu, 4/29/10, Maciej Piechotka
Hein Hundal wrote:
I figured I should try a larger program
converting one of my Mathematica programs, a simulator for the card game Dominion, over to Haskell. Most of
in Haskell, so I am that is going well
except for one patch of imperative code. My Haskell version of this code is ugly. I was hoping someone could recommend a better way to do it. I will paste a simplified version of the code below. If necessary, I can provide all the other code used for
1. Use strong typing. Or any typing
I simplified the code for the post. In the real version, I use strong typing. The Card type is enumerated. I have been using [Card] instead of calling it a Deck. I could change that.
2. User guards instead of nested if's:
In the "procloop" function, I have if's nested quite deeply. I could easily use guards. I will try that.
3. Don't use too much variables. 6-8 is probably the maximum you should deal with (human short-term memory holds about 5-10 points of entry. Split functions into smaller functions (even in where).
I do have to get the information into the functions, so the only way I can avoid having lots of variables is by introducing new structures. I can do that.
4. Discard result you don't need:
isDone (LSt gs strat iA iTh i aA iB iC bDone) = bDone isDone (LSt _ _ _ _ _ _ _ _ _ bDone) = bDone
Yes, that's much better. proc gs' strat = let iA = 1 iTh = 0 i = 0 aA = replicate 20 0 iB = 1 iC = 0 bDone = False gs = apps ("<<<"++show(gs')++">>>") gs' lst = LSt gs strat iA iTh i aA iB iC bDone lst2 = until isDone procloop lst isDone (LSt _ _ _ _ _ _ _ _ bDone) = bDone output (LSt gs _ _ _ _ aA iB iC _) = (iB, iC, appd aA gs) in output lst2
5. Don't reuse the same name in the same scope (like iA as 1 and iA as parameter to isDone).
I did hesitate to use the same parameter name twice.
6. While Haskell have long tradition of having short namesit is not always good (see 3). Use them only if you are sure it is clear what they mean:
In the original version, I had longer variable names where they seemed necessary. The main sources of ugliness are the long lists of variables. Every time I call doAct or construct a LoopState variable, I am repeating all those variables. I will try changing the type of doAct to doAct :: LoopState -> LoopState Cheers, Hein