Haskell中如何提取无限帕斯卡三角嵌套列表的指定列元素
Hey there! Awesome that you've already got an infinite Pascal's triangle implemented as a nested list—extracting the k-th element from each valid row is totally straightforward, and map is absolutely the right tool for the job. Let's break this down step by step.
First, Clarify Indexing
Haskell lists are 0-indexed, but your example (pascal 4 returning 1,4,10,20…) tells us you're likely thinking in 1-based terms for both rows and elements:
- The first element
1is the 4th element of the 4th row (1-based), which translates to the 3rd index of the 3rd row (0-based). - The next element
4is the 4th element of the 5th row (1-based) → 3rd index of the 4th row (0-based), and so on.
Using map with Indexing
Since your infinite triangle is a list of lists ([[Integer]]), we can use map to apply the "get the k-th element" operation to every row. We just need two adjustments:
- Convert your 1-based
kto a 0-based index (subtract 1). - Drop the first
k-1rows, because those rows are too short to have a k-th element (the n-th row (0-based) hasn+1elements total).
Here's the implementation (assuming your infinite triangle is named pascalTriangle):
pascal :: Int -> [Integer] pascal k = map (!! (k-1)) $ drop (k-1) pascalTriangle
Let's test this with your example:
pascal 4translates tomap (!!3) $ drop 3 pascalTriangledrop 3 pascalTrianglegives us rows starting from the 3rd row (0-based):[1,3,3,1], [1,4,6,4,1], [1,5,10,10,5,1], [1,6,15,20,15,6,1], …map (!!3)extracts the 3rd index from each of these rows:1,4,10,20,…which matches exactly what you need!
Why This Works
- Lazy Evaluation: Haskell's laziness means we don't have to compute the entire infinite triangle upfront.
mapanddropwill only generate elements as needed, so the resulting sequence is also infinite and efficient. mapis Perfect Here: We're applying the same pure function (indexing into a list) to every element of the triangle list—this is exactly the use casemapwas designed for.
Alternative: Directly Generate the Sequence (No Triangle Needed)
If you don't need the full triangle anymore, you can skip building it entirely and generate the sequence using binomial coefficient recurrence. The k-th element (1-based) of the n-th row (1-based) is C(n-1, k-1), and we can compute this incrementally without factorials:
import Data.List (scanl') pascal :: Int -> [Integer] pascal k = scanl' (\acc n -> acc * (n + k - 1) `div` n) 1 [1..]
This approach is often more efficient than indexing into a pre-built triangle, as it avoids constructing all the extra elements of each row.
Final Notes
- Add a guard clause if you want to handle invalid inputs:
pascal k | k > 0 = ... | otherwise = error "k must be a positive integer" - If your original triangle uses 0-based element indexing (e.g., you want
pascal 3to return your example sequence), just adjust the code to usekinstead ofk-1in both the index anddropargument.
内容的提问来源于stack exchange,提问作者helloworld

