Haskell列表中的值范围

Haskell列表中的值范围,haskell,Haskell,我正在尝试函数式编程,现在使用Haskell并练习列表理解。我试图定义一个函数来生成一个正方形列表 到目前为止,我有这个功能: squares = map (^2) [2..] 我现在想做的是只在低->高范围内生成正方形。我通常试图找出如何在Haskell列表中指定一系列值。有人可以帮忙吗?您可以使用takeWhile和dropWhile检查项目,只要谓词满足,就可以进行take/drop操作,因此: squares = (dropWhile (< low) . takeWhile (&

我正在尝试函数式编程,现在使用Haskell并练习列表理解。我试图定义一个函数来生成一个正方形列表

到目前为止,我有这个功能:

squares = map (^2) [2..]

我现在想做的是只在低->高范围内生成正方形。我通常试图找出如何在Haskell列表中指定一系列值。有人可以帮忙吗?

您可以使用
takeWhile
dropWhile
检查项目,只要谓词满足,就可以进行take/drop操作,因此:

squares = (dropWhile (< low) . takeWhile (<= high) . map (^2)) [2..]
我现在想做的是在Haskell列表中只在一个范围low->high[…]之间生成正方形

我想你的意思是,你想选择这个范围内的方块,而不是特定范围内的输入,但我会对两者都进行讨论。另外,您目前没有使用列表理解,只是一个列表,但我还将演示如何使用这两个列表

首先,您的原始代码可以用
map
和列表表示,也可以用列表表示

squares = map (^ 2) [2 ..]

squares = [x ^ 2 | x <- [2 ..]]
您可以使用
let
将其绑定到理解中的变量,而不是重复
x^2
表达式:

squaresBetween (low, high) =
  [ s
  | x <- [2 ..]
  , let s = x ^ 2
  , s >= low && s <= high
  ]
当输入为有限列表时,这种带有保护或
过滤器的方法非常合适。但是,由于此处的输入列表是一个无限的数字流(
[2..]
=
enumFrom 2
),因此这两个函数也将产生无限的数据流。一般来说,语言无法知道理解将过滤掉所有的值>
high
,因此它将继续生成和丢弃元素,并且永远不会到达终点。例如,在GHCi中,在打印列表末尾之前,将挂起对此的评估
]

> squaresBetween (0, 100)
[4,9,16,25,36,49,64,81,100
您可以键入Ctrl+C退出此计算,它将显示为
^C
。GHCi将中断打印
并返回提示

解决这个问题的一个方法是使用
takeWhile
dropWhile
等函数来过滤掉元素,而不是使用保护/
过滤器
takeWhile
选择与条件匹配的列表中最长的前缀,然后
dropWhile
删除前缀

squaresBetween (low, high)
  = takeWhile (<= high)     -- 3. Keep those not over ‘high’.
    $ dropWhile (< low)     -- 2. Discard those under ‘low’.
    $ map (^ 2) [2 ..]      -- 1. Generate a stream of squares.
然后(0100)
之间的平方将生成
[2,3,4,5,6,7,8,9,10]
。这些lambda可以写成组合:
(
import Data.Ix (inRange)

squaresBetween (low, high)
  = filter (inRange (low, high))
    $ map (^ 2) [2 ..]

squaresBetween (low, high) =
  [ s
  | x <- [2 ..]
  , let s = x ^ 2
  , inRange (low, high) s
  ]
> squaresBetween (0, 100)
[4,9,16,25,36,49,64,81,100
squaresBetween (low, high)
  = takeWhile (<= high)     -- 3. Keep those not over ‘high’.
    $ dropWhile (< low)     -- 2. Discard those under ‘low’.
    $ map (^ 2) [2 ..]      -- 1. Generate a stream of squares.
between (low, high) = takeWhile (<= high) . dropWhile (< low)

squaresBetween range = between range $ map (^ 2) [2 ..]
squaresBetween range = between range [x ^ 2 | x <- [2 ..]]
squaresBetween (low, high)

  -- 3. Select only the numbers, not their squares.
  = map fst

    -- 2. Keep and discard pairs by their second element.
    $ takeWhile (\ (_x, s) -> s <= high)  
    $ dropWhile (\ (_x, s) -> s < low)

    -- 1. Generate (number, square) pairs.
    $ [(x, x ^ 2) | x <- [2 ..]]
squaresBetween (low, high) =
  [ s
  | x <- [2 .. limit]
  , let s = x ^ 2
  , s >= low && s <= high
  ]
  where
    limit = round (sqrt (fromIntegral high)) + 1
> squaresBetween (0, 100)
[4,9,16,25,36,49,64,81,100]