Following the book "Get programming with Haskell" I stumbled over rather confusing exercise. One of the chapters explains how to make simple objects using closures. So, for instance we have a tuple which describes a primitive robot:
(name, attack, hp). And using this tuple we can construct a robot like this:
robot (name,attack,hp) = \message -> message (name,attack,hp)
for instance:
killerRobot = robot ("Kill3r", 25, 200)
And so on, the author explains how to make accessor functions using this structure:
hp (_,_,hp) = hp
attack (_,a,_) = a
getHP aRobot = aRobot hp
getAttack aRobot = aRobot attack
so we can examine how many hit point the certain robot has:
getHP killerRobot
So far so good and I'm not going to rewrite the entire chapter, but I can't catch one further thing. Next we have a function:
damage aRobot attackDamage = aRobot (\(n,a,h) ->
robot (n,a,h-attackDamage))
and another function
fight aRobot defender = damage defender attack
where attack = if getHP aRobot > 10
then getAttack aRobot
else 0
which emulates a combat between two robots. So we can write something like that:
gentleGiant = robot ("Mr. Friendly", 10, 300)
gentleGiantRound1 = fight killerRobot gentleGiant
killerRobotRound1 = fight gentleGiant killerRobot
gentleGiantRound2 = fight killerRobotRound1 gentleGiantRound1
killerRobotRound2 = fight gentleGiantRound1 killerRobotRound1
gentleGiantRound3 = fight killerRobotRound2 gentleGiantRound2
killerRobotRound3 = fight gentleGiantRound2 killerRobotRound2
and it works just fine. But when I try to put this into a function, which incapsulates these steps and returns the result of the last step (actually the task is slightly different) I get a whole bunch of errors related to type system I guess. I'll show a simplified version which throws errors:
roundFights rb1 rb2 =
let rb2' = fight rb1 rb2
in fight rb2' rb1
The second fight makes compiler explode with errors. All those functions don't have type signatures intentionally - the same thing inside the book - because it's just one of the introductory chapters and type signatures have not yet explained.
Can someone suggest what's wrong?
Here is the source code:
robot (name, attack, hp) = \message -> message (name, attack, hp)
name (nm, _, _) = nm
attack (_, a, _) = a
hp (_, _, p) = p
getName r = r name
getAttack r = r attack
getHP r = r hp
setName r nm = r $ \(_, a, hp) -> robot (nm, a, hp)
setAttack r a = r $ \(nm, _, hp) -> robot (nm, a, hp)
setHP r hp = r $ \(nm, a, _) -> robot (nm, a, hp)
printRobot r = r $ \(nm, a, hp) -> nm ++ " attack:" ++ show a ++ " hp:" ++ show hp
damage r ad = r $ \(nm, a, hp) -> robot (nm, a, hp - ad)
fight atacker defender = damage defender power where
power = if getHP atacker > 10
then getAttack atacker
else 0
lives = map getHP
roundFights rb1 rb2 =
let rb2' = fight rb1 rb2
in fight rb2' rb1
rb1 = robot("Killer", 25, 200)
rb2 = robot("Slayer", 15, 200)
and the errors sheet I get:
D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:27:18:
Occurs check: cannot construct the infinite type:
t8 ~ ((t7, t8, t8) -> t0) -> t0
Expected type: ((t7, t8, t8) -> ((t7, t8, t8) -> t0) -> t0) -> t6
Actual type: ((t7, t8, t8) -> t8) -> t6
Relevant bindings include
rb2' :: ((t4, t5, t5) -> t5) -> t8
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:26:8)
rb2 :: ((t2, t3, t6) -> ((t2, t3, t6) -> t) -> t)
-> ((t4, t5, t5) -> t5) -> t8
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:25:17)
rb1 :: ((t7, t8, t8) -> t8) -> t6
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:25:13)
roundFights :: (((t7, t8, t8) -> t8) -> t6)
-> (((t2, t3, t6) -> ((t2, t3, t6) -> t) -> t)
-> ((t4, t5, t5) -> t5) -> t8)
-> t6
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:25:1)
In the second argument of `fight', namely `rb1'
In the expression: fight rb2' rb1
D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:30:27:
No instance for (Num t1) arising from the literal `200'
The type variable `t1' is ambiguous
Relevant bindings include
rb1 :: (([Char], t1, t1) -> t) -> t
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:30:1)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the expression: 200
In the first argument of `robot', namely `("Killer", 25, 200)'
In the expression: robot ("Killer", 25, 200)
D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:31:27:
No instance for (Num t1) arising from the literal `200'
The type variable `t1' is ambiguous
Relevant bindings include
rb2 :: (([Char], t1, t1) -> t) -> t
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:31:1)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the expression: 200
In the first argument of `robot', namely `("Slayer", 15, 200)'
In the expression: robot ("Slayer", 15, 200)
D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:33:8:
No instance for (Ord t1) arising from a use of `fight'
The type variable `t1' is ambiguous
Relevant bindings include
rb2' :: (([Char], t1, t1) -> t) -> t
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:33:1)
Note: there are several potential instances:
instance Integral a => Ord (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
instance Ord () -- Defined in `GHC.Classes'
instance (Ord a, Ord b) => Ord (a, b) -- Defined in `GHC.Classes'
...plus 24 others
In the expression: fight rb1 rb2
In an equation for rb2': rb2' = fight rb1 rb2
D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:34:8:
No instance for (Ord t1) arising from a use of `fight'
The type variable `t1' is ambiguous
Relevant bindings include
rb1' :: (([Char], t1, t1) -> t) -> t
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:34:1)
Note: there are several potential instances:
instance Integral a => Ord (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
instance Ord () -- Defined in `GHC.Classes'
instance (Ord a, Ord b) => Ord (a, b) -- Defined in `GHC.Classes'
...plus 24 others
In the expression: fight rb2' rb1
In an equation for rb1': rb1' = fight rb2' rb1
D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:35:9:
No instance for (Ord t1) arising from a use of `fight'
The type variable `t1' is ambiguous
Relevant bindings include
rb2'' :: (([Char], t1, t1) -> t) -> t
(bound at D:\Dropbox\Documents\Work\HS\GetProg\Unit 10\Robot.hs:35:1)
Note: there are several potential instances:
instance Integral a => Ord (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
instance Ord () -- Defined in `GHC.Classes'
instance (Ord a, Ord b) => Ord (a, b) -- Defined in `GHC.Classes'
...plus 24 others
In the expression: fight rb1' rb2'
In an equation for rb2'': rb2'' = fight rb1' rb2' Failed, modules loaded: none.
rb1'andrb2'', but they're nowhere in your code). Are you sure you have posted your actual code? Perhaps you have omitted some parts?damagefunction, but I haven't figured out why (it's making me mad without types :P). You can try this definition instead:damage aRobot attackDamage = robot (getName aRobot, getAttack aRobot, getHP aRobot - attackDamage)and it should work.