[英]How to define an infinite 2D array recursively in Haskell?
我是Haskell的新手,我喜欢它优雅的语法。 但我还没有找到一种合适的方法来定义无限的2D数组 - 例如,Pascal三角形:
1 1 1 1 1 ...
1 2 3 4 5 ...
1 3 6 10 15 ...
1 4 10 20 35 ...
1 5 15 35 70 ...
...
我知道如何定义一个简单的函数:
pascal :: Int -> Int -> Int
pascal 1 _ = 1
pascal _ 1 = 1
pascal x y = (pascal (x - 1) y) + (pascal x (y - 1))
由于Haskell不记忆函数值,因此调用pascal 20 20
需要很长时间 。 我怎么能定义一个快速版本(如无限的2D数组)?
您可以将pascal三角形创建为无限,惰性,嵌套列表
pascal :: [[Integer]]
pascal = repeat 1 : map (scanl1 (+)) pascal
上面的定义有点简洁,但它本质上意味着每一行都是前一行的累加和,从repeat 1
开始,即无限的列表。 这样做的好处是我们可以直接计算三角形中的每个值而无需进行任何O(n)索引。
现在,您可以索引列表以查找所需的值,例如
> pascal !! 19 !! 19
35345263800
该列表仅针对您需要的值进行部分评估。
您还可以轻松输出一系列值:
> putStrLn $ unlines $ take 5 $ map (unwords . map show . take 5) $ pascal
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 70
另一种选择是使用原始功能,但使用可用的各种记忆库之一进行记忆。 例如,使用data-memocombinators
:
import Data.MemoCombinators
pascal :: Integer -> Integer -> Integer
pascal = memo2 integral integral pascal'
pascal' :: Integer -> Integer -> Integer
pascal' 1 _ = 1
pascal' _ 1 = 1
pascal' x y = (pascal (x - 1) y) + (pascal x (y - 1))
无限2D“数组”的明显选择是嵌套列表,即无限列表的无限列表。 因此可能是
pascal' :: [[Integer]]
pascal' = repeat 1 : [ 1 : [ pascalGen x y | y<-[1..] ] | x<-[1..] ]
where pascalGen x y = pascal' !! (x-1) !! y + pascal' !! x !! (y - 1)
现在这个函数调用了memoised。 由于列表O ( n )访问,它仍然不是最优的,但也不是那么糟糕。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.