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!

+3


source to share


2 answers


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!

+1


source


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.

+1


source







All Articles