【发布时间】:2011-05-17 00:08:55
【问题描述】:
如果我有一个数据类型说:
data Color = Red | Yellow | Green
有没有办法可以把它变成一个 [Color] 类型的列表来获取所有可能的值? [红、黄、绿]
也许这是一个完整的反模式?
【问题讨论】:
-
我相信 [toEnum 0 ..] 无论您如何更改数据定义都有效。
如果我有一个数据类型说:
data Color = Red | Yellow | Green
有没有办法可以把它变成一个 [Color] 类型的列表来获取所有可能的值? [红、黄、绿]
也许这是一个完整的反模式?
【问题讨论】:
不确定它是否是反模式(我现在也想不出有什么好的用途),但有可能。使用Enum(允许生成类似[someCtor .. someOtherCtor] 的列表)和Bounded(用于minBound 和maxBound)类型类。幸运的是,您可以同时导出两者:
data Color = Red
| Yellow
| Green
deriving (Enum, Bounded)
allColors = [(minBound :: Color) ..]
如果您添加了另一种颜色,allColors 会自动更新。但是有一个限制:Enum 要求所有构造函数都是无效的,即添加 Foo Int 会破坏整个过程。幸运的是,因为所有可能值的列表都太大了。
编辑:另一个答案也可以,可能更好,因为它不需要派生Bounded,因此更短一些。我仍然会离开我的,因为我喜欢过度设计但非常通用的代码;)
【讨论】:
当然,delnan 的答案更好。由于我不知道如何在评论中包含一段代码,因此我将在此处给出一个概括作为单独的答案。
allValues :: (Bounded a, Enum a) => [a]
allValues = [minBound..]
现在,这适用于具有Bounded 和Enum 实例的任何类型!而allColors只是一个特例:
allColors :: [Color]
allColors = allValues
在许多情况下,您甚至不需要单独定义 allColors。
【讨论】:
data Color = Red
| Yellow
| Green
deriving Enum
allColors = [Red ..]
【讨论】:
| Pink时,这将被打破。
[toEnum 0 ..] 无论您如何更改数据定义都有效。
这里是使用 Parsec 解析枚举的示例
data FavoriteColor = Maroon | Black | Green | Red |
Blue | Pink | Yellow | Orange
deriving (Show, Read, Enum, Bounded)
还有解析器解析器
parseColor :: Parser FavoriteColor
parseColor = fmap read . foldr1 (<|>) $ map (try . string . show)
[ minBound :: FavoriteColor ..]
当然,可以通过模式匹配更好地应用尝试,其他一些事情可以使它更好,但这只是该技术的一些使用示例。
【讨论】: