Haskell中的Pascal三角形

Haskell中的Pascal三角形,haskell,recursion,pascals-triangle,Haskell,Recursion,Pascals Triangle,我是哈斯克尔的新手,我真的需要一些帮助 我必须编写一个程序,其中包含一个递归函数,使用Pascal的三角形技术生成n=12次方的二项式系数列表 我脑子里有一些想法,但因为我才刚刚开始,我不知道如何将这些实现给haskell 有人能帮我吗 first row: (a+b)^0 = 1 second row: (a+b)^1 = 1a+1b third row: (a+b)^2 = 1a^2+2ab+1b^2 等等……这是我的主要想法。但是我甚至不能尝试这个,因为我不知道我是如何把它放在Haske

我是哈斯克尔的新手,我真的需要一些帮助

我必须编写一个程序,其中包含一个递归函数,使用Pascal的三角形技术生成n=12次方的二项式系数列表

我脑子里有一些想法,但因为我才刚刚开始,我不知道如何将这些实现给haskell

有人能帮我吗

first row: (a+b)^0 = 1
second row: (a+b)^1 = 1a+1b
third row: (a+b)^2 = 1a^2+2ab+1b^2

等等……这是我的主要想法。但是我甚至不能尝试这个,因为我不知道我是如何把它放在Haskell中的。总是出错

从基本情况开始

pascal 0 0 = 1
然后处理边缘情况

pascal n 0 = 1
pascal n r | n == r = 1
现在展开递归步骤

pascal n r = pascal (n - 1) (r - 1) + pascal (n - 1) r
如果需要特定行的列表,请编写包装器

binom n = map (pascal n) [0..n]
弄清楚类型应该不难

pascal :: Integral a => a -> a -> a
binom :: Integral a => a -> [a]

首先为三角形中的每个元素指定索引:

| 0 1 2 3 4 5 6 --+-------------------------- 0 | 1 1 | 1 1 2 | 1 2 1 3 | 1 3 3 1 4 | 1 4 6 4 1 5 | 1 5 10 10 5 1 6 | 1 6 15 20 15 6 1 这样您就可以生成这个版本的三角形。你可以从写作开始

pascal x y
    | x == 0 = 1
    | x == y = 1
    | x <  y = error "Not a valid coordinate for Pascal's triangle."
    | otherwise = pascal ? ? + pascal ? ?
不要试图把这个解决方案交给你的教授,这不是他们想要的,如果你只做了一个星期的Haskell,很明显有人给了你这个解决方案。然而,它确实显示了Haskell对于这类问题的能力。我将展示如何索引
pascal
以获得给定的
(n,k)
值,但这样做也会为您提供太多解决幼稚递归的提示

由于存在一些混淆,我给出此解决方案的原因是将其与经常显示的Fibonacci序列的惰性实现进行比较:

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
相比

fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

这个定义生成了一个包含所有斐波那契数的无限列表,而且非常有效(从CPU的角度来看,RAM是另一回事)。它在其前2个元素中编码基本情况,然后是一个可以计算其余内容的递归表达式。对于Fibonaccis,你需要两个值来开始,但是对于Pascal三角形,你只需要一个值,这个值恰好是一个无限列表。在我上面发布的网格中,有一个很容易看到的模式穿过列,
scanl1(+)
函数正好利用了这个模式,并允许我们非常容易地生成它,但这是生成三角形的对角线,而不是行。要获取行,您可以为该列表编制索引,也可以使用
take
drop
,以及其他类似功能执行一些奇特的操作,但这是另一天的练习。

从三角形本身开始:

     1
    1 1
   1 2 1
  1 3 3 1
 1 4 6 4 1
    ...
您应该注意到,要写下下下一行,您必须应用以下规则:对前一行的相邻元素求和,对孤立边缘元素使用
0
。视觉上:

    0   1   0
     \+/ \+/
  0   1   1   0
   \+/ \+/ \+/
0   1   2   1   0
 \+/ \+/ \+/ \+/
  1   3   3   1
       ...
在操作上,这看起来是这样的:

For row 0:
[1]  (it's a given; i.e. base case)

For row 1:
[0, 1]   <- row 0 with a zero prepended ([0] ++ row 0)
 +  +
[1, 0]   <- row 0 with a zero appended  (row 0 ++ [0])
 =  =
[1, 1]   <- element-wise addition

For row 2:
[0, 1, 1]
 +  +  +
[1, 1, 0]
 =  =  =
[1, 2, 1]

Generally, for row N:

element-wise addition of:
  [0] ++ row(N-1)
  row(N-1) ++ [0]
或者以类似于著名的“懒惰的谎言”的方式:

另一种可能的解决方案(我认为更适合初学者):

使用
避免。
pascal
递归调用以查找前面的所有行,使用它们获取下一行,直到到达所需的行

输出:

*Main> pascal 3
[1,3,3,1]
*Main> pascal 4
[1,4,6,4,1]
*Main> pascal 5
[1,5,10,10,5,1]

你试过什么?你应该自己尝试解决这个问题,尽量说得更具体一些。老实说,这听起来像是一个家庭作业问题,重点是学习,而不是实际的实施。你尝试了什么,你在哪里遇到了困难?例如,你找到了帕斯卡三角形的公式并实现了吗?你理解三角形和二项式系数之间的关系吗?是的,我理解三角形和二项式系数之间的关系。这实际上是一个家庭作业问题,我知道理论上我需要做什么。但我们一周前才开始Haskell,但我认为这个问题对于像我这样从未与Haskell合作过的人来说太复杂了。所以我知道该怎么做,但我在Haskell语法方面遇到了问题。pascals函数似乎会产生一个无限的1列表。@nclark您必须从每个子列表中获取一些,因此
map(take 10)pascals
将提供您要查找的内容。否则,在ghci中,您只需设置它,并尝试计算帕斯卡的第一个元素,这应该是一个1的无限列表。@bheklillr
map(take 10)帕斯卡
不会产生第10行。该代码生成对角线,对第n个元素进行索引将生成偏移量无限的对角线。
For row 0:
[1]  (it's a given; i.e. base case)

For row 1:
[0, 1]   <- row 0 with a zero prepended ([0] ++ row 0)
 +  +
[1, 0]   <- row 0 with a zero appended  (row 0 ++ [0])
 =  =
[1, 1]   <- element-wise addition

For row 2:
[0, 1, 1]
 +  +  +
[1, 1, 0]
 =  =  =
[1, 2, 1]

Generally, for row N:

element-wise addition of:
  [0] ++ row(N-1)
  row(N-1) ++ [0]
pascal 0 = [1]
pascal n = zipWith (+) ([0] ++ pascal (n-1)) (pascal (n-1) ++ [0])
pascals = [1] : map (\xs -> zipWith (+) ([0] ++ xs) (xs ++ [0])) pascals
pascal :: Integer -> [Integer]
pascal 0 = [1]
pascal 1 = [1, 1]
pascal n = let p = pascal (n - 1)
    in [1] ++ pascalStep p ++ [1]

pascalStep :: [Integer] -> [Integer]
pascalStep [] = []
pascalStep [_] = []
pascalStep (x:y:xs) = x + y : pascalStep (y : xs)
*Main> pascal 3
[1,3,3,1]
*Main> pascal 4
[1,4,6,4,1]
*Main> pascal 5
[1,5,10,10,5,1]