使用`streamInterleave`实现标尺功能

时间:2019-03-25 02:57:36

标签: haskell stream infinite self-reference interleave

我正在做CIS 194的作业。问题是通过使用streamInterleave来实现标尺功能。代码看起来像

data Stream a = Cons a (Stream a)

streamRepeat :: a -> Stream a
streamRepeat x = Cons x (streamRepeat x)

streamMap :: (a -> b) -> Stream a -> Stream b
streamMap f (Cons x xs) = Cons (f x) (streamMap f xs)

streamInterleave :: Stream a -> Stream a -> Stream a
streamInterleave (Cons x xs) ys = Cons x (streamInterleave ys xs)

ruler :: Stream Integer
ruler = streamInterleave (streamRepeat 0) (streamMap (+1) ruler)

我真的很困惑为什么可以像这样实现标尺。这会给我[0,1,0,1....]吗?

任何帮助将不胜感激。谢谢!!

2 个答案:

答案 0 :(得分:1)

首先,我们将这样表示一个Stream

a1 a2 a3 a4 a5 ...

现在,让我们来分开ruler的定义:

ruler :: Stream Integer
ruler = streamInterleave (streamRepeat 0) (streamMap (+1) ruler)

在Haskell中,重要的一点是懒惰。也就是说,在需要对事物进行评估之前,不需要对其进行评估。这一点很重要:这就是使此无限递归定义起作用的原因。那么我们如何理解呢?我们将从streamRepeat 0位开始:

0 0 0 0 0 0 0 0 0 ...

然后将其馈送到streamInterleave中,并与来自streamMap (+1) ruler(用x代表)的(尚未知道)流进行交织:

0 x 0 x 0 x 0 x 0 x 0 x ...

现在,我们将开始填写这些x。我们已经知道ruler的每个第二元素是0,所以streamMap (+1) ruler的每个第二元素必须是1

  1   x   1   x   1   x   1   x   1   x ... <--- the elements of (streamMap (+1) ruler)
0 1 0 x 0 1 0 x 0 1 0 x 0 1 0 x 0 1 0 x ... <--- the elements of ruler

现在我们知道每四个元素中的第二个元素(因此数字2,6,10,14,18,...)为1,因此streamMap (+1) ruler的相应元素必须是2

  1   2   1   x   1   2   1   x   1   2 ... <--- the elements of (streamMap (+1) ruler)
0 1 0 2 0 1 0 x 0 1 0 2 0 1 0 x 0 1 0 2 ... <--- the elements of ruler

现在我们知道八组中的每四个元素(所以数字4,12,20,...)为2,因此streamMap (+1) ruler的对应元素必须为{{1 }}:

3

我们可以通过重新替换每个 1 2 1 3 1 2 1 x 1 2 ... <--- the elements of (streamMap (+1) ruler) 0 1 0 2 0 1 0 3 0 1 0 2 0 1 0 x 0 1 0 2 ... <--- the elements of ruler 编号为ruler的{​​{1}}来继续构建n/2, 3n/2, 5n/2, ...,就像这样的 ad infinitum

答案 1 :(得分:1)

在Haskell表示法中,用Stream代替ruler = interleave (repeat 0) (map (+1) ruler) [ruler !! i | i <- [0..]] == concat . transpose $ [ repeat 0 , map (+1) ruler] (这对无限列表是同形的),

ruler

[ruler !! 2*i | i <- [0..]] == repeat 0 == [0 | i <- [0..]] -- {0} -- [ruler !! 2*i+1 | i <- [0..]] == map (+1) ruler == map (+1) $ concat . transpose $ [ [ruler !! 2*i | i <- [0..]] , [ruler !! 2*i+1 | i <- [0..]]] concat . transpose $ == concat . transpose $ [[ruler !! 2*i+1 | i <- [0,2..]] [ [1 | i <- [0..]] ,[ruler !! 2*i+1 | i <- [1,3..]]] , [1 + ruler !! 2*i+1 | i <- [0..]]] 分成两个交替的子序列以进行匹配,我们得到

  [ruler !! 4*i+1 | i <- [0..]]   == [1 | i <- [0..]]         -- {1} --

  [ruler !! 4*i+3 | i <- [0..]]   == concat . transpose $
                                       [ [1 + ruler !! 2*i+1 | i <- [0,2..]]
                                       , [1 + ruler !! 2*i+1 | i <- [1,3..]]]

再次分裂

  [ruler !! 8*i+3 | i <- [0..]]   == [2 | i <- [0..]]         -- {2} --

  [ruler !! 8*i+7 | i <- [0..]]   == ....

再次

      .... 16*i+7             .....   3                       -- {3} --
      .... 32*i+15            .....   4                       -- {4} --
      .... 64*i+31            .....
      ....

您应该可以从这里看到它:

    ruler !! 2^(k+1)*i + 2^k - 1   ==   k    ,  k <- [0..] ,  i <- [0..]

0: i => 2i
1:      2i+1 => 4i+1
2:              4i+3 => 8i+3
3:                      8i+7 => 16i+7
4:                              16i+15 => ....
5:                                     

因此

<connectionStrings>
    <add name="Cons" 
    connectionString="data source=.\PT.sqlite"
    providerName="System.Data.SQLite"/> 
</connectionStrings>