Haskell定义列表和列表理解

时间:2013-05-03 14:01:41

标签: list haskell list-comprehension

早上好!

我正在尝试定义一个列表,该列表包含我之前定义的所有可能的地址类型,并使用列表解析来执行此操作。

以下是我早期定义的内容,可能对您有所帮助:

data Row = A | B | C | D | E | F | G | H | I | J deriving (Enum, Ord, Show, Bounded, Eq, Read)
data Column = One | Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten  deriving (Enum, Ord, Show, Bounded, Eq, Read)
data Address = Address Row Column deriving (Show, Read, Eq)
data Cell = Cell Address Bool deriving (Show, Read, Eq)

我不确定我是否需要在此解决方案中使用Cell,但也许。

这是我目前的解决方案,我想知道是否有人提出改进建议,或者可能只是完全错误。任何指导将不胜感激!

allAddressesA = [ x * y | x <- [Row] y <- [Column]]

仅供参考,这是一份正式的书面要求:

  

将allAddressesA定义为所有可能的电路板地址列表。使用   列表推导使用行和列类型的范围。

谢谢!我会密切关注这一点,所以请随时询问您需要澄清的任何内容。我感谢您花时间阅读本文并提供建议:)

2 个答案:

答案 0 :(得分:8)

你写道:

  

这是我目前的解决方案,我想知道是否有人   关于改进它的建议,或者它可能只是完全错误。

当然是否完全错误可以很容易地进行测试。只需输入并询问您的编译器:

allAddressesA = [ x * y | x <- [Row] y <- [Column]]
我说:

parse error on input `<-'

我认为这符合错误。

所以,让我们先修复语法。列表理解的第二部分中可能的多个子句(|之后的部分,即)将用逗号分隔。这样做会给出:

allAddressesA = [ x * y | x <- [Row], y <- [Column]]

编译器对此有何看法?

Not in scope: data constructor `Row'
Not in scope: data constructor `Column'

实际上,RowColumn是类型构造函数而不是数据构造函数。这意味着您可以使用它们来构建类型表达式,但不能构建“普通”值表达式。

显然,我们走错了路。那么让我们退一步吧。

您的Row类型和Column类型都属于类型类EnumBounded。因此,我们可以轻松地分别生成包含所有行和列指示符的列表:

allRows    = [minBound :: Row    .. maxBound]
allColumns = [minBound :: Column .. maxBound]

(使用minBoundmaxBound会使您的代码比使用AJ以及OneTen更加强大,从某种意义上说,向RowColumn添加构造函数并不需要您更改allRowsallColumns的定义。)

在交互式环境中,我们可以轻松评估这些列表。实际上,打印allRows给出了:

> allRows
[A,B,C,D,E,F,G,H,I,J]

allColumns我们得到

> allColumns
[One,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten]

现在,由于地址由行和列指示符组成,因此生成所有可能的地址只会简化为获取所有行和所有列的叉积。通过之前对allRowsallColumns的定义,我们可以轻松地将这样的交叉产品编写为列表理解:

allAddresses = [Address row column | row <- allRows, column <- allColumns]

由于您有10个行指示符和10个列指示符,因此您最终会得到一个10 x 10 = 100个地址的列表:

> length allAddresses
100

为了娱乐,让我们打印前15:

> take 15 allAddresses
[Address A One,Address A Two,Address A Three,Address A Four,Address A Five,
Address A Six,Address A Seven,Address A Eight,Address A Nine,Address A Ten,
Address B One,Address B Two,Address B Three,Address B Four,Address B Five]

答案 1 :(得分:3)

以下是代码的骨架:

allAddressesA = [ Address {- ... -} | x <- [A .. J], y <- [{- ... -}]]

使用正确的代码替换每个{- ... -}

data Address = Address Row Column

意味着您可以使用名为Address的构造函数创建类型为Address的复合数据,该函数需要两个参数:第一个类型为Row,第二个类型为{ {1}}。在指定范围时,我们会显示数据元素,而不是类型或课程:我们写Column,而不是[1 .. 10]