什么时候使用Haskell类型类的权威指南?

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能够理解并遵循我的代码,那么这种"普遍接受"的方式是什么?

Fix*_*num 7

大多数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这样的库来提供可扩展的记录,为您提供一种子类型.