使用Haskell实现面向对象编程
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
评论已关闭