jmi*_*ite 4 haskell types functional-programming typeclass
所以,我非常了解代数类型和类型类,但我对它的软件工程/最佳实践方面很感兴趣.
对于类型类,现代共识是什么?他们是邪恶的吗?它们方便吗?它们应该被使用吗?
这是我的案例研究.我正在写一个RTS风格的游戏,我有不同类型的"单位"(坦克,侦察等).说我想获得每个单位的最大健康状况.关于如何定义类型的两个想法如下:
ADT的不同构造函数:
data Unit = Scout ... | Tank ...
maxHealth :: Unit -> Int
maxHealth Scout = 10
maxHealth Tank = 20
Run Code Online (Sandbox Code Playgroud)
单元的类型类,每种类型都是一个实例
class Unit a where
maxHealth :: a -> Int
instance Unit Scout where
maxHealth scout = 10
instance Unit Tank where
maxHealth tank = 20
Run Code Online (Sandbox Code Playgroud)
显然,最终产品中会有更多的领域和功能.(例如,每个单元将具有不同的位置等,因此并非所有功能都是恒定的).
诀窍是,可能有些功能对某些单元有意义,但对其他单元则不然.例如,每个单位都有一个getPosition函数,但是坦克可能有一个getArmour函数,对于没有装甲的侦察兵来说没有意义.
如果我希望其他Haskeller能够理解并遵循我的代码,那么这种"普遍接受"的方式是什么?
大多数Haskell程序员都对不必要的类型类不满.这些伤害类型的推断; 你甚至不能制作Unit没有技巧的s 列表; 在GHC中,有所有秘密字典传递; 他们以某种方式使哈多克斯难以阅读; 他们可以导致脆弱的等级制度......也许其他人可以给你更多的理由.我想一个好的规则就是在避免使用它们时更加痛苦.例如,没有Eq,你必须手动传递函数来比较两个[[[Int]]](或使用一些临时运行时测试),这是ML编程的难点之一.
看一下这篇博客文章.你使用总和类型的第一种方法是好的,但是如果你想让用户用新单位或其他什么来修改游戏,我会建议像
data Unit = Unit { name :: String, maxHealth :: Int }
scout, tank :: Unit
scout = Unit { name = "scout", maxHealth = 10 }
tank = Unit { name = "tank", maxHealth = 20 }
allUnits = [ scout
, tank
, Unit { name = "another unit", maxHealth = 5 }
]
Run Code Online (Sandbox Code Playgroud)
在你的例子中,你需要编码一个坦克有装甲的地方但是一个侦察兵没有.显而易见的可能性是使用诸如Maybe Armor字段或特殊权力列表之类的额外信息来增加单位类型......这不一定是明确的方式.
一个重量级的解决方案,可能是矫枉过正,是使用像Vinyl这样的库来提供可扩展的记录,为您提供一种子类型.