使用列表理解的指数化

时间:2017-04-22 08:27:52

标签: haskell functional-programming

我正在尝试解决以下练习(我正在学习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元素列表,给出错误的结果。对此有任何想法将不胜感激。

3 个答案:

答案 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..]等无限列表,则需要一些 思考。我们可以构建headfilter,这意味着我们可以获得 从无限列表到与谓词匹配的第一个元素,这看起来像是一种获取递归函数的方法。我没有 认为它是一个问题,因为它们只是算术序列和 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

相关问题