[英]calculate `[1, x^1, x^2, …, x^n]` in Haskell
我如何像下面这样在Haskell中编写powerList
函数? 我想用n
乘法运算来构建这样一个列表,其中每个元素都是前一个元素的简单倍数,而不是n
指数运算。
理想情况下,实现是干净,惯用的Haskell,并且相当有效。
-- powerList x n -> [1, x, x^2, ..., x^n]
-- For example:
-- powerList 2 0 -> [1]
-- powerList 2 1 -> [1, 2]
-- powerList 2 2 -> [1, 2, 4]
-- powerList 2 3 -> [1, 2, 4, 8]
-- powerList 2 4 -> [1, 2, 4, 8, 16]
powerList :: forall a. Integral a => a -> a -> [a]
powerList _ 0 = [1]
powerList x n = [] -- ???
对于每个元素都是前一个元素的函数的列表,可以使用iterate
:
iterate :: (a -> a) -> a -> [a]
iterate fx
返回f
到x
的重复应用的无限列表:iterate fx == [x, fx, f (fx), ...]
Prelude> powerList x n = take (n + 1) $ iterate (* x) 1
Prelude> powerList 2 0
[1]
Prelude> powerList 2 4
[1,2,4,8,16]
如果你想不使用iterate
或take
的做法,我想通过看如何开始iterate
实现:
iterate f i = i : iterate f (f i)
为了执行类似的操作,我们的递归函数将需要一个附加参数i
。 在编写递归函数时,这是一种非常常见的技术。
-- powerList x n = [ 1, x, x^2, ..., x^n ]
powerList x n = powerList' n 1
where
-- powerList' n i = [ i, i*x, i*x^2, ..., i*x^n ]
powerList' 0 i = [ i ]
powerList' n i = i : powerList' (n - 1) (i * x)
列表理解通常是生成器的简写。 生成器在其他功能中有多种用途。 列表理解通常足够简洁,可以在函数中内联。 以下是powerList函数的列表理解版本。 它简称为p。 我很懒。 结果中的两个值是每个值的笛卡尔积。 也是第一个参数的常数仅需要一次。 去搞清楚。
Prelude> p i j = [(k ^ n) | k <- [i], n <- [0..j]]
Prelude> p 2 16
[1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536]
大笑的事实是,i或k是常量和参数,可以使用。
p i j = [(i ^ n) | n <- [0..j] ]
我发现Haskell最引人注目的是,上面的函数是规范而不是指令。 Haskell的许多功能告诉计算机需要什么,而不是做什么来获得它,也就是说,它具有很大的说明性,这是语言中最想要的。
编辑4/5/2018,我很抱歉。 我的最后一个函数未满足您将最后一个值乘以一个因子的规范。 您的规范实际上是递归的。 “其中每个元素都是前一个元素的简单倍数,而不是n个指数运算。” 下面的函数正是这样做的。
pow l = l ++ pow [(last l) * 2]
但是就像迭代一样,它是无限的。 使用take x $ pow [1]
使其不会永远运行。
克里斯的答案很可能就是您想要的。
如果您想在不使用迭代的情况下进行操作,则可以使用以下代码。
编辑:为避免附加到列表的尾部(花费线性时间),可以使用辅助函数powerList'
首先反向计算列表,然后反转该函数的输出以更正顺序。
powerList' :: Integral a => a -> a -> [a]
powerList' _ 0 = [1]
powerList' x n = do { let l = go x (n - 1)
; [x * (head l)] ++ l
}
powerList :: Integral a => a -> a -> [a]
powerList x n = reverse (powerList' x n)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.