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