Can anyone explain this error? Could not match type 'Integer'
I am trying to learn haskell and there is a certain error that I cannot figure out.
robot (_name,_attack,_hp) = \ cmd -> cmd (_name,_attack,_hp)
hp (_,_,h) = h
getHp aRobot = aRobot hp
setHp aRobot newHp = aRobot (\ (n,a,_) -> robot (n,a,newHp))
damage aRobot amount = let actualHp = getHp aRobot
in
setHp aRobot (actualHp - amount)
makeKiller = robot ("Killer",10,200)
makeBetty = robot ("Betty",5,300)
----- Example of computation in ghci
b = makeBetty
b1 = damage b 34
<interactive>:52:14: error:
* Couldn't match type `Integer'
with `(([Char], Integer, t1) -> t0) -> t0'
Expected type: (([Char], Integer,
(([Char], Integer, t1) -> t0) -> t0)
-> (([Char], Integer, t1) -> t0) -> t0)
-> t1
Actual type: (([Char], Integer, Integer) -> t1) -> t1
* In the first argument of damage, namely `b'
In the expression: damage b 34
In an equation for `b1': b1 = damage b 34
* Relevant bindings include b1 :: t1 (bound at <interactive>:52:1)
There is something wrong with the damage function, can someone explain the error to me please?
Thank you in advance!
source to share
This code needs the Rank2Types extension.
Robot Betty has the type ((String, Integer, Integer) â t) â t. This type must be polymorphic.
Functional damage is taken by the robot (its type is (String, Integer, Integer) â t) â t) as an argument. This function has rank 2 polymorphism.
{-# LANGUAGE Rank2Types #-}
type Robot = forall t . ((String, Integer, Integer) -> t) -> t
robot :: (String, Integer, Integer) -> Robot
robot (_name,_attack,_hp) = \ cmd -> cmd (_name,_attack,_hp)
hp :: (String, Integer, Integer) -> Integer
hp (_,_,h) = h
getHp :: Robot -> Integer
getHp aRobot = aRobot hp
setHp :: Robot -> Integer -> Robot
setHp aRobot newHp = aRobot (\ (n,a,_) -> robot (n,a,newHp))
damage :: Robot -> Integer -> Robot
damage aRobot amount = let actualHp = getHp aRobot
in
setHp aRobot (actualHp - amount)
makeKiller :: Robot
makeKiller = robot ("Killer",10,200)
makeBetty :: Robot
makeBetty = robot ("Betty",5,300)
If there are no rank 2 types, the robot types that require getHp and setHp are incompatible. The getHp function requires ((String, Integer, Integer) -> Integer) -> Integer as a robot type. And the setHp function requires ((String, Integer, Integer) -> Robot) -> Robot.
A simplified version is here.
fun :: (a -> a) -> Char -> Int -> (Char, Int)
fun f c n = (f c, f n)
This definition raises a type error.
{-# LANGUAGE Rank2Types #-}
fun :: (forall a . a -> a) -> Char -> Int -> (Char, Int)
fun f c n = (f c, f n)
This definition is fine!
source to share
You probably don't need a robot to be a function, just declare it as a type that has a tuple:
type Robot = (String, Integer, Integer)
getHp :: Robot -> Integer
getHp (_, _, hp) = hp
setHp :: Robot -> Integer -> Robot
setHp (name, attack, _) hp = (name, attack, hp)
damage :: Robot -> Integer -> Robot
damage r dmg = setHp r $ getHp r - dmg
makeKiller :: Robot
makeKiller = ("Killer", 10, 200)
makeBetty :: Robot
makeBetty = ("Betty", 5, 300)
b = makeBetty
b1 = damage b 34
Alternatively, you can make Robot an algebraic datatype , which is definitely better than just using a tuple.
source to share