adr*_*usi 5 haskell metaprogramming
我想使用haskell来实现一个游戏,并希望使用类型系统来实现项目系统.它会像这样工作:
data Wood = Wood Int
instance Item Wood where
image a = "wood.png"
displayName a = "Wood"
instance Flammable Wood where
burn (Wood health) | health' <= 0 = Ash
| otherwise = Wood health'
where health' = health - 100
Run Code Online (Sandbox Code Playgroud)
Item和Flammable类是这样的:
class Item a where
image :: a -> String
displayName :: a -> String
class Flammable a where
burn :: (Item b) => a -> b
Run Code Online (Sandbox Code Playgroud)
为此,我需要一种方法来检测值是否是类型类的实例.
Data.Data模块提供了类似的功能,这使我相信这是可能的.
去类型类可能是错误的方式.请考虑使用普通代数数据类型,例如:
data Item = Wood Int | Ash
image Wood = "wood.png"
image Ash = ...
displayName Wood = "Wood"
displayName Ash = "Ash"
burn :: Item -> Maybe Item
burn (Wood health) | health' <= 0 = Just Ash
| otherwise = Just (Wood health')
where health' = health - 100
burn _ = Nothing -- Not flammable
Run Code Online (Sandbox Code Playgroud)
如果这使得添加新项目变得太难,则可以在数据类型本身中对操作进行编码.
data Item = Item { image :: String, displayName :: String, burn :: Maybe Item }
ash :: Item
ash = Item { image = "...", displayName = "Ash", burn :: Nothing }
wood :: Int -> Item
wood health = Item { image = "wood.png", displayName = "Wood", burn = Just burned }
where burned | health' <= 0 = ash
| otherwise = wood health'
health' = health - 100
Run Code Online (Sandbox Code Playgroud)
但是,这使得添加新功能变得更加困难.同时做两者的问题被称为表达问题.RalfLämmel博士在第9频道上进行了很好的讲座,他更深入地解释了这个问题并讨论了各种非解决方案,如果你有时间,值得观看.
有解决它的方法,但它们比我说明的两个设计复杂得多,所以如果它符合你的需要,我建议使用其中一个,除非你必须,否则不要担心表达问题.
这是问题所在:
burn :: (Item b) => a -> b
Run Code Online (Sandbox Code Playgroud)
这意味着结果值burn
必须是多态的.它必须能够为任何实例填充任何空洞.Item
现在,很明显你正在尝试编写类似这样的东西(用虚构的OO语言编写接口和子类):
Interface Item {
String getImage();
String getDisplayName();
}
Interface Flammable {
Item burn();
}
Run Code Online (Sandbox Code Playgroud)
在这种代码中,你会说burn
会生成一些项目,而不保证它是什么类型的项目.这是"为所有人"和"存在"之间的区别.您想在Haskell代码中表达的是"存在",但您实际表达的是"为所有人".
现在,如果你真的确定要办"存在"的功能,你可以看看用存在主义类型.但要注意.如果您打算编写如下代码:
if (foo instanceof Flammable) {
...
}
Run Code Online (Sandbox Code Playgroud)
然后你几乎肯定做错了,会遇到很多痛苦和痛苦.相反,考虑一下hammar提出的替代方案.