使用枚举类型:列出,比较和构建直方图

时间:2016-04-16 14:50:32

标签: haskell enumeration

我最近完成(自学)homework assignment of some UPenn Haskell Course构建Mastermind求解器。

作业从

的定义开始
data Color = Red | Green |  Blue |  Yellow | Orange |  Purple deriving (Eq, Show)

type Code = [Color]

涉及枚举类型的各种操作。虽然我设法complete the assignment,但有几个部分我认为我的代码不必要地重复或低效:

  1. 为了枚举长度为 n 的所有代码(即Color值的长度 n 的所有笛卡尔组合),我&# 39;使用了

    allColors = [Red, Green, Blue, Yellow, Orange, Purple]
    

    这似乎是重复和脆弱的,因为它只是Color的所有可能性。有没有办法单独定义枚举,然后从它们建立一个列表?从概念上讲,我喜欢像allColors = listAll(Color)这样的问题(问题是什么是listAll)。

  2. 由于许多表达式包含(if l == r then 1 else 0)(其中lrColor s),我最终写了一个{{ 1}}功能。当然有一些方法可以比较两种枚举类型并将结果更容易地转换为整数,不是吗?即,我希望boolToInt评估为1,Red == Red评估为0。

  3. 部分解决方案需要从Red == Blue构建直方图,我使用

    Code

    这似乎既低效又冗长。有没有更短更有效的方法呢?

2 个答案:

答案 0 :(得分:3)

1)如果我们定义

data Color = Red | Green |  Blue |  Yellow | Orange | Purple
   deriving (Eq, Show, Enum, Bounded, Ord)

然后我们可以使用

> [minBound .. maxBound] :: [Color]
[Red,Green,Blue,Yellow,Orange,Purple]

2)要将布尔值转换为整数,我们可以使用

> fromEnum True
1
> fromEnum False
0

3)对于直方图,我们可以从排序和分组开始:

> import Data.List
> map (\xs -> (head xs, length xs)) . group . sort $ [Red, Red, Blue, Red]
[(Red,3),(Blue,1)]

添加零作为练习。

使用数组而不是列表可以通过删除O(log n)因子来提高性能,但我要避免这种情况,除非我们知道性能在这里真的很重要。

答案 1 :(得分:3)

对于1.和3.请参阅chi's suggestion

对于2.我建议你避免在递归函数中手动添加计数器。在Haskell中使用标准的高阶函数通常更为惯用。例如,countColor只给出了履行谓词的子列表的长度。因此,我会将其实现为

countColor c = length . filter (==c)

类似地,

exactMatches ls rs = length . filter id $ zipWith (==) ls rs