你写:
这是我目前的解决方案,我想知道是否有人对改进它有建议,或者它可能完全是错误的。
当然可以很容易地测试它是否完全错误。只需输入并询问您的编译器:
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'
确实,Row
并且Column
是类型构造函数而不是数据构造函数。这意味着您可以使用它们来构建类型表达式,但不能构建“普通”值表达式。
显然,我们走错了路。所以让我们退后几步。
你的Row
类型和你的Column
类型都在类型类Enum
和Bounded
. 因此,我们可以轻松地分别生成包含所有行和列指示符的列表:
allRows = [minBound :: Row .. maxBound]
allColumns = [minBound :: Column .. maxBound]
(使用minBound
andmaxBound
使您的代码比立即使用A
and J
,andOne
和 and更健壮Ten
,因为将构造函数添加到Row
andColumn
不需要您更改allRows
and的定义allColumns
。)
在交互式环境中,我们可以轻松评估这些列表。事实上,印刷allRows
给出了:
> allRows
[A,B,C,D,E,F,G,H,I,J]
因为allColumns
我们得到
> allColumns
[One,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten]
现在,由于地址由行和列指示符组成,生成所有可能的地址简单地简化为取所有行和所有列的叉积。有了前面对allRows
and的定义allColumns
,我们可以很容易地写出这样的叉积作为列表推导式:
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]