用let和show显示haskell中的列表理解,它是什么用的?

时间:2018-05-17 21:21:21

标签: haskell list-comprehension

我正在研究项目欧拉解决方案,这是问题4的解决方案,其中要求

  

找到由两个3位数的产品制成的最大的回文   编号

problem_4 =
  maximum [x | y<-[100..999], z<-[y..999], let x=y*z, let s=show x, s==reverse s]

我了解此代码会创建一个列表,x是所有可能的zy的产品。

但是我在理解s这里做了什么时遇到了问题。每当需要此列表中的新元素时,看起来|之后的所有内容都会被执行,对吧?

我认为我不明白这里发生了什么。 |右边的所有内容都不应该是约束吗?

2 个答案:

答案 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表达式的片段被视为guardControl.Monad函数的参数。 guard的作用是使评估短路;对于列表monad,这意味着不会对导致错误参数的return x的特定值执行x

答案 1 :(得分:4)

  

我认为我不明白这里发生了什么。 |右边的所有内容都不应该是约束吗?

不,在右边部分,您会看到一个逗号分隔(,)“部分”列表的表达式,并且每个部分都是以下树之一:

  1. somevar <- somelist;
  2. 形式的“生成器”
  3. let语句,这是一个表达式,可用于例如引入存储子结果的变量;和
  4. 布尔类型的表达式,其行为类似于过滤器
  5. 所以它不是某种“约束编程”,其中一个人只能列出一些约束并希望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声明为yz的乘法,let s = show x,我们基本上转换一个数字(例如15129)到其字符串对应部分(例如“15129”)。最后,我们使用s == reverse s来反转字符串并检查它是否等于原始字符串。

    请注意,有更有效的方法来测试Palindromes,特别是两个数字的乘法。