Haskell中类似OO的接口实现 [英] OO-Like interface implementation in Haskell

查看:151
本文介绍了Haskell中类似OO的接口实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管标题我不会问OO世界和哈斯克尔之间的纯粹翻译,但我无法弄清楚一个更好的标题。这个讨论和这一个类似,但并不相同。



我已经开始了一个玩具项目,只是为了扩展我对Haskell有限的知识,同时阅读学习你对一个伟大的好东西的Haskell,并且我已经决定实现一个非常基本的元素类型系统,它是诸如Final Fantasy et simila等游戏中典型战斗系统的子集。
我跳过了大部分细节,但这简单来说就是我的问题:



我想塑造一个咒语,一个可以施展的魔法玩家还是怪物。在OO世界中,您通常会使用onCast(Player)方法来创建一个Castable接口,这是一个Spell类,因此您可以定义像这样的事物。

 拼写myNewSpell = Spell(Fire,100,20); 
myNewSpell.onCast(Player p); //为Fire的行为建立模型

在Haskell中,我认为这是根据类型和类我知道Haskell中的类是一个不同的概念!)。我遇到了一些困难,因为我的第一次尝试是创建这个:

   - 一个类型synonim,一个元组(HP ,MP)
类型CastResult =(整数,整数)


- 一个可施法咒语可以造成伤害(或恢复)或
- 触发一个状态
类Castable s其中
onCast :: s - >或者(可能状态)CastResult


数据Spell = Spell {spellName :: String,
spellCost :: Integer,
spellHpDmg :: Integer,
spellMpDmg :: Integer,
spellElem ::可能元素}派生(Eq,Show,Read)



<现在假设我使用记录语法来创建一些咒语

$ p code bio = Spell {spellName =Bio,... etc ..}

我希望能够做到这一点

  instance Castable bio其中
onCast bio = Left(Just Poison)

这里有很多问题:
$ b $ 1)我不能做Castable生物,因为生物必须是具体类型,而不是类型的值(它应该是可施放的法术)b / b
2)生物不在范围内,在实例区块内被看作是一个模式值与

匹配总的来说,我感觉这个ch设计的风格很差,但我仍然在学习,而且我没有掌握像Functors这样的高级主题,只是为了举一个名字。



简而言之,这是处理这种情况的惯用方式吗?我的意思是这种情况需要一个定义,多个实例的多个实现,只是使用OO术语。 p>

Alfredo

解决方案

类型。然而,在这种情况下,我觉得你好像在处理单独的实例。在这种情况下,将cast功能设置为另一个记录字段可能是最简单的。

  data Spell = Spell {spellName: :字符串,
...
onCast :: Either(可能状态)CastResult}
派生(Eq,Show,Read)

bio = Spell {spellName = Bio,onCast = Left(Just Poison),...}

或者你可以做一些事情它可以更明确地模拟您的需求,使用特定于域的类型而不是像或者这样的通用类型。

  type ManaPoints =整数
类型HitPoints =整数

数据Spell = Spell {spellName :: String,
spellCost :: ManaPoints,
spellElem ::可能元素,
spellEffect ::效果}

数据效果=伤害HitPoints ManaPoints
| inflict状态

cast :: Spell - >玩家 - >玩家
施放法术玩家=
case spellEffect法术
伤害hp法力= ...
施放状态= ...

bio = Spell { spellName =Bio,spellEffect = Inflict Poison,...}
fire = Spell {spellName =Fire,spellEffect = Damage 100 0,...}


despite the title I'm not going to ask about a mere translation between OO world and Haskell, but I can't figure out a better title. This discussion is similar, but not equal, to this one.

I've started a toy project just to expand my limited knowledge of Haskell while reading "Learn You a Haskell for a Great Good", and I've decided to implement a very basic "Elemental Type System", which is a subset of a typical battle system in games like Final Fantasy et simila. I'm skipping most of the details, but this is in a nutshell my problem:

I want to model a spell, a magic you can cast on the player or on a monster. In the OO world you usually go for a "Castable" interface with a method "onCast(Player)", a "Spell" class so you can define thing like this

Spell myNewSpell = Spell("Fire", 100, 20);
myNewSpell.onCast(Player p); //models the behaviour for the Fire spell

In Haskell I thought this in terms of Types and Classes (I know that Classes in Haskell are a different concept!). I've encountered some difficulties, because my first attempt was to create this:

--A type synonim, a tuple (HP,MP)
type CastResult = (Integer,Integer)


--A castable spell can either deal damage (or restore) or
--inflict a status
class Castable s where
  onCast :: s -> Either (Maybe Status) CastResult


data Spell = Spell{spellName :: String,
                   spellCost :: Integer,
                   spellHpDmg :: Integer,
                   spellMpDmg :: Integer,
                   spellElem :: Maybe Element} deriving (Eq,Show,Read)

Now suppose I create some spell using the Record Syntax

bio = Spell{spellName = "Bio", ...etc..}

I would like be able to do something like this

instance Castable bio where
  onCast bio = Left (Just Poison)

There are many problems here:

1) I can't do "Castable bio" since bio must be a concrete type, not a value of the Type (It should be Castable Spell)

2) bio isn't in scope, inside the instance block is seen just as a value to pattern match against

Overall, I feel this choice of design is pretty poor, but I'm still learning and I don't grasp such advanced topics like Functors, just to name one.

In a nutshell, which is the idiomatic way to dealing with situation like this? I mean situation wich requires "one definition, multiple implementation for multiple instances", just to use the OO terminology.

Thanks everyone, happy coding,

Alfredo

解决方案

Type classes are useful when you're dealing with different types. In this case, however, it seems to me like you're dealing with separate instances. In such a case, it's probably simplest to have the cast function be just another record field.

data Spell = Spell{spellName :: String,
                   ...
                   onCast :: Either (Maybe Status) CastResult }
    deriving (Eq,Show,Read)

bio = Spell { spellName = "Bio", onCast = Left (Just Poison), ... } 

Or you could do something that models your requirements more explicitly, using domain-specific types rather than generic ones like Either.

type ManaPoints = Integer
type HitPoints  = Integer

data Spell = Spell { spellName :: String,
                     spellCost :: ManaPoints,
                     spellElem :: Maybe Element,
                     spellEffect :: Effect }

data Effect = Damage  HitPoints ManaPoints
            | Inflict Status

cast :: Spell -> Player -> Player
cast spell player =
    case spellEffect spell of
        Damage hp mana = ...
        Inflict status = ...

bio  = Spell { spellName = "Bio", spellEffect = Inflict Poison, ... }
fire = Spell { spellName = "Fire", spellEffect = Damage 100 0, ... }

这篇关于Haskell中类似OO的接口实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆