如何在Haskell中编写n
函数,如下所示?我希望用n
乘法运算构建这样一个列表,其中每个元素都是前一个元素的简单倍数,而不是-- 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 = [] -- ???
指数运算。
理想情况下,实现是干净的,惯用的Haskell,并且相当有效。
FindFirst()
答案 0 :(得分:12)
对于每个元素都是前一个元素的函数的列表,您可以使用https://github.com/ccnokes/electron-tutorials/tree/master/preload-scripts:
iterate :: (a -> a) -> a -> [a]
iterate f x
会返回f
到x
重复申请的无限列表:iterate f x == [x, f x, f (f x), ...]
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)
答案 1 :(得分:2)
列表推导通常是生成器的简写。生成器在其他功能中用于许多目的。列表推导通常足够简洁,可以在函数中包含内联。以下是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]
LOL一个明显的事实,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]
不要让它永远运行。
答案 2 :(得分:1)
克里斯的回答很有可能是你要找的。 p>
如果您不想使用iterate,可以使用以下代码。
编辑:为了避免附加到列表尾部(需要线性时间),可以使用辅助函数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)