我正在研究项目欧拉解决方案,这是问题4的解决方案,其中要求
找到由两个3位数的产品制成的最大的回文 编号
problem_4 =
maximum [x | y<-[100..999], z<-[y..999], let x=y*z, let s=show x, s==reverse s]
我了解此代码会创建一个列表,x
是所有可能的z
和y
的产品。
但是我在理解s
这里做了什么时遇到了问题。每当需要此列表中的新元素时,看起来|
之后的所有内容都会被执行,对吧?
我认为我不明白这里发生了什么。 |
右边的所有内容都不应该是约束吗?
答案 0 :(得分:5)
列表推导是do
表达式的一个相当薄的包装:
problem_4 = maximum $ do
y <- [100..999]
z <- [y..999]
let x = y*z
let s = show x
guard $ s == reverse s
return x
大多数作品直接翻译;不是迭代器(<-
)或let
表达式的片段被视为guard
中Control.Monad
函数的参数。 guard
的作用是使评估短路;对于列表monad,这意味着不会对导致错误参数的return x
的特定值执行x
。
答案 1 :(得分:4)
我认为我不明白这里发生了什么。
|
右边的所有内容都不应该是约束吗?
不,在右边部分,您会看到一个逗号分隔(,
)“部分”列表的表达式,并且每个部分都是以下树之一:
somevar <- somelist
; let
语句,这是一个表达式,可用于例如引入存储子结果的变量;和所以它不是某种“约束编程”,其中一个人只能列出一些约束并希望Haskell能够找出它(事实上,就个人而言,“编程语言”和“规范语言”:在编程语言中,您可以“控制”数据如何以规范语言流动,由读取您的规范的系统处理)
基本上,迭代器可以与许多命令式编程语言中的“foreach”循环进行比较。 “let”语句可以看作是引入一个temprary变量(但请注意,在Haskell中你做 not 赋值变量,你声明它们,所以你不能重新分配值)。过滤器可以看作是if
语句。
因此列表理解将等同于Python中的某些内容:
for y in range(100, 1000):
for z in range(y, 1000):
x = y * z
s = str(x)
if x == x[::-1]:
yield x
我们首先以嵌套的方式迭代两个范围,然后我们将x
声明为y
和z
的乘法,let s = show x
,我们基本上转换一个数字(例如15129
)到其字符串对应部分(例如“15129”)。最后,我们使用s == reverse s
来反转字符串并检查它是否等于原始字符串。
请注意,有更有效的方法来测试Palindromes,特别是两个数字的乘法。