我正在尝试解决以下练习(我正在学习Haskell):
使用列表推导定义x ^ n。
我正在努力寻找解决方案。
使用递归或折叠,解决方案并不复杂(例如,foldr (*) 1 [x | c <- [1..n]]
)。但是,仅使用列表理解会变得困难(至少对我而言)。
为了解决这个问题,我正在尝试创建一个x ^ n元素列表,然后获取长度。生成x * n元素列表很容易,但是我无法生成x ^ n元素列表。
ppower x n = length [1 | p <- [1..x], c <- [1..n]]
返回一个x * n元素列表,给出错误的结果。对此有任何想法将不胜感激。
答案 0 :(得分:3)
自然发生的指数来自sequence
:
length (sequence [[1..x] | _ <- [1..n]])
如果您还没有看到sequence
,那么这是一个非常普遍的功能但是
当与列表一起使用时,它的工作方式如下:
sequence [xs1, ... , xsk] = [[x1, ... xk] | x1 <- xs1, ... , xk <- xsk]
但由于sequence
是递归定义的,所以这真的是在作弊。
如果你想只使用长度和列表理解,我想 这可能是不可能的。这个答案的其余部分将是粗略的,我一半 期待有人证明我错了。但是:
我们将尝试证明这样的表达式只能计算出值 到 x 或 n 的某些有限功率,因此无法计算值 对于任意 x 和 n , x ^ n 一样大。
具体而言,我们通过归纳表示表达式的结构 任何表达式 expr 都有一个上限 ub(expr,m)= m ^ k 其中 m 是它使用的自由变量的最大值, k 是已知的有限变量 我们可以根据表达式 expr 的结构计算出的能力。
(当我们查看整个表达式时, m 将 max x n 。)
列表表达式的上界将在列表的长度上绑定,也可以在任何一个上绑定 它的元素(及其元素的长度等)。
例如,如果我们有[x..y]
且我们知道 x&lt; = m 且 y&lt; = m ,我们
知道所有元素都是&lt; = m ,长度也是&lt; = m 。
所以我们有 ub([x..y],m)= m ^ 1 。
棘手的案例是列表理解:
[eleft | x1 <- e1, ... , xk <- ek]
结果的长度等于长度e1 * ... *长度ek ,所以 它的上限将是上限的乘积 e1 到 ek ,或者如果 m ^ i 是这些中的最大值那么上限 将是(m ^ i)^ k = m ^(i * k)。
要获取元素的界限,假设表达式 eleft 具有 ub(eleft,m&#39;)= m&#39; ^ j 。它可以使用 x1 ...... xk 。如果 m ^ i 是这些的上限,如上所述,我们需要 拿 m&#39; = m ^ i 所以 ub(eleft,m)=(m ^ i)^ j = m ^(i * j)
作为整个列表理解 e 的保守上限我们 可以采用 ub(e,m)= m ^(i * j * k)。
我还应该完成模式匹配的案例
(不应该是一个问题,因为匹配的部分小于
我们已经拥有的),let
定义和功能(但我们禁止了
递归,所以我们可以在开始之前完全展开这些,并且
列出像[x,37,x,x,n]
这样的文字(我们可以抛弃它们
进入 m 作为最初可用的值)。
如果允许使用[x..]
或[x,y..]
等无限列表,则需要一些
思考。我们可以构建head
和filter
,这意味着我们可以获得
从无限列表到与谓词匹配的第一个元素,这看起来像是一种获取递归函数的方法。我没有
认为它是一个问题,因为它们只是算术序列和
2.我们必须构建我们想要使用的任何数字
谓语。但我不确定这里。
答案 1 :(得分:1)
正如@n.m建议的那样,我向Richard Bird(本书的作者&#34;函数式编程简介&#34;第一版,我参加练习的那本书)请求解答这个练习的答案/指导。他好心地回答,我在这里发布他给我的答案:
由于列表推导返回的列表不是数字,因此x ^ n不能 定义为列表推导的实例。你的解决方案x ^ n = 产品[x | c&lt; - [1..n]]是正确的。
所以,我想我会坚持我发布的解决方案(并因使用递归而丢弃):
foldr (*) 1 [x | c <- [1..n]]
尽管@David Fletcher和@n.m在他们的评论中指出,但他并没有说明创建一个包含列表理解(没有递归)的x ^ n元素列表,但这可能是不可能的。
答案 2 :(得分:0)
可能你可以这样做;
pow :: Int -> Int -> Int
pow 0 _ = 1
pow 1 x = x
pow n x = length [1 | y <- [1..x], z <- [1..pow (n-1) x]]
所以pow 3 2
会返回8