我有一个递归的Haskell函数,它接受一个数字n并生成一个列表,该列表是从1开始的n个平方数字。
代码有效,但是n = 3的列表不是[9,4,1]我希望它是[1,4,9]。
sqNList :: Int -> [Int]
sqNList 0 = []
sqNList n = n*n : sqNList (n-1)
我尝试过swappig:for a ++但是模式匹配不起作用。我今天刚刚开始使用Haskell所以可能很明显
答案 0 :(得分:6)
最好的方法是根据从1到n的辅助函数来实现sqNList
。这样你就可以在第一时间以正确的顺序生成列表。
sqNList :: Int -> [Int]
sqNList n = sqNListHelper 1 n
sqNListHelper :: Int -> Int -> [Int]
sqNListHelper current end = ...
有各种各样的更复杂的方法,但这是交互式调试/测试的最简单方法,同时也让您了解如何自己完成所有事情。
更复杂的方法可以包括列表推导或组合函数,如map
和enumFromTo
,以便从更简单的部分构建逻辑。
答案 1 :(得分:5)
消耗可能最少内存的最简单方法是使用累加器:您传递的参数并通过每次递归调用进行更新。
现在你使用 n 作为累加器,并递减,但我们可以决定使用累加器 i 而不是从1
开始,并且保持递增:
helper :: Int -> Int -> [Int]
helper i n | i > n = []
| otherwise = i*i : helper (i+1) n
现在我们当然必须自己使用i = 1
来调用它,这不是理想的,但我们可以使用where
子句来限制helper
中sqNList
的范围:
sqNList :: Int -> [Int]
sqNList n = helper 1 n
where helper :: Int -> Int -> [Int]
helper i n | i > n = []
| otherwise = i*i : helper (i+1) n
现在我们可以改善这一点。对于instanc,无需通过n
调用helper
,因为它不会更改,并且在顶级定义:
sqNList :: Int -> [Int]
sqNList n = helper 1
where helper :: Int -> [Int]
helper i | i > n = []
| otherwise = i*i : helper (i+1)
此外,无需仅使用Int
:我们可以使用a
和Num a
的任何类型Ord a
:
sqNList :: (Num a, Ord a) => a -> [a]
sqNList n = helper 1
where helper i | i > n = []
| otherwise = i*i : helper (i+1)
答案 2 :(得分:3)
这是一种更先进的技术,因此您可能希望将其保存以供将来学习。
大多数递归函数倾向于使用相同的一般递归形式之一,因此知道使用哪个高阶函数可以省去重新实现(可能不正确)递归的工作量,并让您专注于独特的工作你的问题。
这种特殊类型的递归由unfoldr
中定义的Data.List
函数捕获,它允许您使用生成器函数和初始种子值生成(可能是无限的)列表。
它的定义可以像
一样简单unfoldr f x = case f x of
Nothing -> []
Just (new, next) = new : unfoldr f next
虽然实际定义对于效率而言稍微复杂一些。
基本上,您只需在种子值f
上调用生成器x
。如果结果为Nothing
,则返回空列表。否则,构建一个包含结果的列表和一个带有新种子值的递归调用生成的列表。
将此应用于您的问题,只要输入仍然足够小,我们就会生成一个正方形和下一个整数。
import Data.List (unfoldr)
sqNList n = unfoldr generator 1
where generator x = if x > n then Nothing else Just (x*x, x+1)
因此,对于像sqNList 3
这样的简单示例,它按如下方式进行:
generator 1
并返回Just (1, 2)
;累加器现在是[1]
。generator 2
并返回Just (4, 3)
;累加器现在
[1,4]
。generator 3
并返回Just (9, 4)
;累加器现在是[1,4,9]
。generator 4
并返回Nothing
。返回累加器[1,4,9]
作为结果。请注意,只需永远不返回Nothing
即可生成所有方块的无限列表:
allSquares = unfoldr (\x -> Just (x*x, x+1)) 1
Haskell是懒惰的,只在你需要的时候在列表中生成元素,所以你也可以通过只获取无限列表中的第一个sqNList
项来定义n
。
sqNList n = take n (unfoldr (\x -> Just (x*x, x+1)) 1)