haskell - Haskell 中的类 OO 接口(interface)实现

标签 haskell types interface

尽管标题我不会询问 OO 世界和 Haskell 之间的单纯翻译,但我想不出更好的标题。此讨论与 this one 类似,但不相等。 .
我开始了一个玩具项目,只是为了扩展我对 Haskell 的有限知识,同时阅读“Learn You a Haskell for a Great Good”,我决定实现一个非常基本的“元素类型系统”,它是一个子集最终幻想等游戏中的典型战斗系统。
我跳过了大部分细节,但简而言之,这是我的问题:
我想模拟一个咒语,一种你可以对玩家或怪物施放的魔法。在 OO 世界中,您通常会使用带有方法“onCast(Player)”的“Castable”接口(interface),一个“Spell”类,因此您可以定义这样的东西

Spell myNewSpell = Spell("Fire", 100, 20);
myNewSpell.onCast(Player p); //models the behaviour for the Fire spell
在 Haskell 中,我从类型和类的角度来考虑这一点(我知道 Haskell 中的类是一个不同的概念!)。我遇到了一些困难,因为我的第一次尝试是创建这个:
--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)
现在假设我使用记录语法创建了一些咒语
bio = Spell{spellName = "Bio", ...etc..}
我希望能够做这样的事情
instance Castable bio where
  onCast bio = Left (Just Poison)
这里有很多问题:
  • 我不能做“Castable bio”,因为 bio 必须是具体类型,而不是 Type 的值(应该是 Castable Spell)
  • bio 不在范围内,在实例 block 内部被视为模式匹配的值

  • 总的来说,我觉得这种设计选择很差,但我还在学习,我没有掌握像 Functors 这样的高级主题,仅举一个例子。
    简而言之,处理这种情况的惯用方法是什么?我的意思是需要“一个定义,多个实例的多个实现”的情况,只是为了使用 OO 术语。

    最佳答案

    当您处理不同的类型时,类型类很有用。但是,在这种情况下,在我看来,您正在处理单独的实例。在这种情况下,让 cast 函数成为另一个记录字段可能是最简单的。

    data Spell = Spell{spellName :: String,
                       ...
                       onCast :: Either (Maybe Status) CastResult }
        deriving (Eq,Show,Read)
    
    bio = Spell { spellName = "Bio", onCast = Left (Just Poison), ... } 
    

    或者您可以使用特定领域的类型而不是像 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 - Haskell 中的类 OO 接口(interface)实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7430520/

    相关文章:

    haskell - 使用包含保留关键字的字段名解析 JSON

    haskell - 是否可以在派生 Generic 的记录数据类型中列出字段的名称和类型?

    haskell - 使用过滤器进行列表理解的最有效方法

    sql - 您通常将哪种 T-SQL 数据类型用于权重和长度?

    java - 我可以在外观设计模式中有一个接口(interface)吗?

    haskell - Haskell 中的递归

    c# - 如何从存储的运行时类型构建列表或数组类型以便进行比较?

    swift - 给定大小的集合作为 Swift 类型

    c# - mysql外部访问

    java - 如何随意使用接口(interface)方法?