1. 使用Impredicative Polymorphism(不推荐)

使用类型Robot来模拟class Robot,使用State来模拟Robot class的属性值,使用类型Robot -> a来模拟输出类型为a的getter方法,使用Robot->a->Robot或(Robot, Robot )->a->(Robot, Robot)类型的函数模拟setter方法或改变多个对象状态的方法。其中gentleGiant killerRobot fastRobot 和slowRobot 是4个Robot对象实例,robotList保存这4个对象

以下是源代码:

{-# LANGUAGE ImpredicativeTypes #-}
-- State是Robot类的所有属性
type State = (String, Int, Int)
-- Robot 类
type Robot = forall t. ((State -> t) -> t)

-- Robot类的构造方法
robot :: State-> Robot
robot s f = f s

name :: State -> String
name (n,x,y) = n

attack :: State -> Int
attack (x,a,y) = a

hp :: State -> Int
hp (x,y,hp) = hp
-- name getter
getName :: Robot -> String
getName r = r name
-- attack getter
getAttack :: Robot -> Int
getAttack r = r attack
-- HP getter
getHP :: Robot -> Int
getHP  r = r hp
-- name setter
setName :: Robot -> String -> Robot
setName aRobot newName = aRobot (\(n,a,h) -> robot (newName,a,h))
-- attack setter
setAttack :: Robot -> Int -> Robot
setAttack aRobot newAttack = aRobot (\(n,a,h) -> robot (n,newAttack,h))
-- HP setter
setHP :: Robot -> Int -> Robot
setHP aRobot newHP = aRobot (\(n,a,h) -> robot (n,a,newHP))
-- print方法
printRobot aRobot = aRobot (\(n,a,h) -> n ++ " attack:" ++ (show a) ++ " hp:" ++ (show h))
-- 对象的被打方法 aRobot被打,attackDamage是敌人对他的伤害
-- 相当于 aRobot.damage(attackDamage);
damage :: Robot -> Int -> Robot
damage aRobot attackDamage = aRobot (\(n, a, h) -> robot (n, a, h - attackDamage))
-- defender的被打方法,被aRobot打
-- 相当于defender.fight(aRobot);
fight :: Robot -> Robot -> Robot
fight aRobot defender = damage defender attack
    where attack = if (getHP aRobot) > 10
                   then (getAttack aRobot)
                   else 0
-- 这些实例都是Robot类的
gentleGiant, killerRobot, fastRobot, slowRobot :: Robot
gentleGiant = robot ("Mr. Friendly", 10, 300) 
killerRobot = robot ("Kill3r",25,200)
fastRobot = robot ("speedy", 15, 40)
slowRobot = robot ("slowpoke",20,30)
-- Robot列表
robotList :: [Robot]
robotList = [gentleGiant, killerRobot, slowRobot]
-- 获取列表中所有对象的HP
getHPList :: [Robot] -> [Int]
getHPList = map getHP
-- 两个对象对打,返回这两个对象
-- 相当于oneRoundFight(&r1, &r2);
oneRoundFight :: (Robot,  Robot) -> (Robot, Robot)
oneRoundFight (r1, r2) = (fight r2 r1, fight r1 r2)
-- 两个对象对打,返回这两个对象
-- 相当于threeRoundFight(&r1, &r2);
threeRoundFight :: (Robot, Robot) -> (Robot, Robot)
threeRoundFight (r1, r2) = if (getHP s1) > (getHP s2) then (s1,s2) else (s2,s1) 
                           where (s1, s2) = oneRoundFight (oneRoundFight (oneRoundFight (r1, r2)))


main :: IO()
main = do let (winner, loser) = threeRoundFight (gentleGiant, killerRobot)
          print (printRobot winner)
          print (printRobot loser)
          

2. 使用record syntax(更容易实现OOP)

type Name = String 
type Attack = Int
type HP = Int
data Robot = Robot { 
               name :: Name,
               attack :: Attack,
               hp :: HP } 


-- name setter
setName :: Robot -> Name -> Robot
setName r newName = r { name = newName}

-- attack setter
setAttack :: Robot -> Attack -> Robot
setAttack r newAttack = r { attack=newAttack}


-- HP setter
setHP :: Robot -> HP -> Robot
setHP r newHP = r { hp= newHP}


-- print方法
printRobot r = name r ++ " attack:" ++ (show $ attack r) ++ " hp:" ++ (show $ hp r)


damage r attackDamage = setHP r $ hp r - attackDamage


fight aRobot defender = damage defender attackDamage
    where attackDamage = if (hp aRobot) > 10
                   then (attack aRobot)
                   else 0

getHPList = map hp

oneRoundFight (r1, r2) = (fight r2 r1, fight r1 r2)

nRoundFight 1 (r1, r2) = oneRoundFight (r1, r2)
nRoundFight n (r1, r2) = oneRoundFight $ nRoundFight (n-1) (r1, r2)

aoeFight aRobot rList = map (fight aRobot) rList 

-- 这些实例都是Robot类的
gentleGiant, killerRobot, fastRobot, slowRobot :: Robot
gentleGiant = Robot {name="Mr. Friendly", attack=10, hp=300} 
killerRobot = Robot {name="Kill3r",attack=25,hp=200}
fastRobot = Robot {name="speedy", attack=15, hp=40}
slowRobot = Robot {name="slowpoke",attack=20,hp=30}

-- Robot列表
robotList :: [Robot]
robotList = [gentleGiant, killerRobot, slowRobot]

main :: IO()
main = do let (r1,r2) = nRoundFight 10 (gentleGiant, killerRobot)
          print $printRobot r1
          print $printRobot r2
          print $getHPList robotList
          let newList = aoeFight fastRobot robotList
          print $getHPList newList

Haskell也可以使用Type Families实现函数类型多态

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeFamilies #-}

class F a where
    type Out a :: * 
    f :: a -> Out a

instance F String where  
    type Out String = String
    f = show . length

instance F Int where 
    type Out Int = String 
    f = show 

instance F Float where 
    type Out Float = Float
    f = id  

标签: none

评论已关闭