Functional Programming (13)-Infinite data stream-infinite stream

Source: Internet
Author: User

In the previous section, we mentioned that the main difference between stream and list is the lazy evaluation feature of stream. We also discussed that when dealing with large array datasets, the stream can move the data elements into memory one at a time and can be processed on an elemental basis. This makes me think of our common data-search reads: A large amount of data is stored in a database, like an infinite source of data. We embed data-reading methods (those database read-write API functions) into the operation function of the stream, and the data search condition into the stream constructor (constructor) forms a description of the data search operation. This generated stream is only read from the database one at a time when we invoke database records that match the search criteria. This is a very familiar scene, but we often think about its principles.

In many cases, we need infinite data streams (infinite stream) to produce data in a regular and iterative manner, either directly or in some algorithmic way. The infinite data stream is defined as "corecursive": the recursive characteristics are complex to simple and finally terminated, while the characteristics of the infinite data flow are simple to complex and never end.

Let's start with a simple infinite stream of data: a digital generator:

1 def ones:stream[int] = cons (1,ones)              //> ones: = = Ch5.genstream.stream[int]  2 Ones.take (5). ToList                               //> Res0:list[int] = List (1, 1, 1, 1, 1)

The ones function can produce an infinite stream of data. Each element is a constant 1. From this simple example we can take a little taste of the reverse recursion: cons (1,ones), which generates infinite data by repeating the cons of the operation.

We can embed some algorithms into the infinite data flow generation process:

1def Constant[a] (A:A): stream[a] =cons (A, constant (a))2                                                   //> Constant: [A] (A:A) ch5.genstream.stream[a]3Constant (5). Take (5). toList//> Res1:list[int] = List (5, 5, 5, 5, 5)4 5def from (N:int): stream[int] = cons (n, from (n+1))//> From: (n:int) Ch5.genstream.stream[int]6From (5). Take (5). toList//> Res2:list[int] = List (5, 6, 7, 8, 9)7 8def fibs:stream[int] = {9def go (Prev:int, cur:int): stream[int] = {TenCons (Prev,go (Cur,prev +cur)) One     } AGo (0,1) -}//> fibs: = ch5.genstream.stream[int] -Fibs.take (5). toList//> Res3:list[int] = List (0, 1, 1, 2, 3)

From these examples we can see that we are repeating ourselves in the cons. The cons parameter is the result of the algorithm implementation.

The following unfold is one of the most common stream builder functions, and we need to do some important things about it:

 1  def Unfold[a,s] (z:s) (f:s = option[( A, S)]): Stream[a] = {  F (z) match { 3  case  None => ;  empty  4   cons (A, unfold (s) (f))  5  }  6 } // > unfold: [A, S] (z:s) (f:s = option[(A, S)]) Ch5.genstream.stream[a]   

Unfold's work mimics a state-flow process: Z is a starting state and represents a value of a type. The user (caller) then provides an action function f. F's style is: s = = option[(a,s)], meaning to accept a state, and then convert it into a pair of new a value and the new state S, and then put them into an Option. If option is none, this gives the user a chance to terminate the operation and let the unfold stop recursion. You can see two cases of F (z) match {} from the source code of unfold. It should be noted that the function f is for the type S of z operation, type A is stream[a] element type. F's focus is on converting s to the new S. We use some examples to illustrate:

1 def Constantbyunfold[a] (A:A): stream[a] = unfold (A) (_ = = Some ((a,a)))2                                                   //  > Constantbyunfold: [A] (A:A) ch5.genstream.stream[a]3 constantbyunfold (2). Take (5). toList                //> Res4:list[int] = List (2, 2, 2, 2, 2)

Constantbyunfold produces an infinite constant: A also represents the element type and state. _ = = Some ((a,a)) means that regardless of the input state, the element value and state are not changed, so unfold will produce the same number. In addition the result of F can never be none, so this is an infinite data stream (infinite stream).

One more example:

1 def frombyunfold (s:int): stream[int] = unfold (s) (s = = Some (s,s+1))2                                                   /// > Frombyunfold: (s:int) Ch5.genstream.stream[int] 3 frombyunfold (5). Take (5). ToList                    //> Res5:list[int] = List (5, 6, 7, 8, 9)

Frombyunfold produces an infinite sequence of integers starting with S: s representing both the element type and the state. _ = = Some ((s,s+1)) indicates that the new a value is S, the new state is s+1, so the new S = S + 1. The state transition principle can be understood from the results of changing s+1 to s+2 operations:

1 def frombyunfold_2 (s:int): stream[int] = unfold (s) (s = = Some (s,s+2))2                                                   /// > Frombyunfold_2: (s:int) Ch5.genstream.stream[int] 3 frombyunfold_2 (5). Take (5). ToList                  //> Res6:list[int] = List (5, 7, 9, one, one)

Try a different type of status example:

 1  def fibsbyunfold:stream[int] = unfold ( 0,1) {case  (A1,A2) = Some ((A1, (A2, A1+a2)))  2  // > fibsbyunfold: = = Ch5.genstream.stream[int]  3  Fibsbyunfold.take (Ten). ToList > Res8:list[int] = List (0, 1, 1, 2, 3, 5, 8, in.)   

In the example above: The S type is a tuple, the starting value (0,1), and the element type A is int. function F:int = = option[(int, int)]. The F function returns the new A=A1, the new state s (A2, A1+A2). Because the status is a tuple type, (A1,A2) is a pattern-matching operation, so a case must be added. s= (0,1) >>> (a,s) = (0, (1,0+1)) >>> (1, (1,1+1)) >>> (1, (2,2+1)) >>> (2, (3,2+3)) > >> (3, (5,3+5)) >>> (5, (8,5+8)) >>> (8, (13,8+13)) from the above inference we can conclude that a>>> 0,1,1,2,3,5,8,13, while the state s>>> (0,1), (a), (in), (2,3), (3,5), (5,8) ... Constantly changing.?

Here's an example of a more state shift: The map function implemented with unfold

1def mapbyunfoldinfinite[b] (f:a = B): stream[b] = {2 unfold (uncons) {3              CaseSome ((h,t)) =Some ((f (h), Some ((T.head, T.tail) ))4              Case_ =None5         }6     }7(Frombyunfold (1). Mapbyunfoldinfinite {_ + ten}). Take (5). ToList8                                                   //> Res9:list[int] = List (one, one, all, +)

The S type is uncons type >>>option[(A, Stream[a]), and the new state of Uncons is Some ((T.head, T.tail)). Because we use the data structure embedded design, so must use Uncons to represent the stream, its next state is some ((T.head, T.tail)). If you use Subclass mode cons (H,t), then the next state can be directly represented by T, which is much more concise.

Let's see what else can be accomplished with unfold:

1def takebyunfold (N:int): stream[a] = {2 unfold ((uncons,n)) {3              Case(Some ((h,t)), K)if(k > 0) = Some (H, (Some (T.head, T.tail)), k-1))4              Case_ =None5         }6     }7def takewhilebyunfold (f:a = Boolean): stream[a] = {8 unfold (uncons) {9              CaseSome ((h,t))if(f (h)) =Some (H, Some ((T.head, T.tail)))Ten              Case_ =None One         } A     } -def filterbyunfold (f:a = Boolean): stream[a] = { - unfold (uncons) { the              CaseSome ((h,t))if(f (h)) =Some (H, Some ((T.head, T.tail))) -              Case_ =None -         } -     } +def Zipwithbyunfold[b,c] (B:stream[b]) (f: (A, B) + C): stream[c] = { - unfold ((uncons,b.uncons)) { +                  Case(Some (Ha,ta)), Some ((HB,TB)) =Some (f (HA,HB), (Some ((Ta.head,ta.tail)), Some ((tb.head,tb.tail) ))) A                  Case_ =None at             } -         } -def Zip[b] (B:stream[b]): stream[(A, b)] =Zipwithbyunfold (b) {(_, _)} -(Frombyunfold (1). Mapbyunfoldinfinite {_ + ten}). Take (5). ToList -                                                   //> Res9:list[int] = List (one, one, all, +) -(Frombyunfold (1). Mapbyunfoldinfinite {_ + ten}). Takebyunfold (5). ToList in                                                   //> Res10:list[int] = List (one, one, all, +) -(Frombyunfold (1). Mapbyunfoldinfinite {_ + ten}). Takewhilebyunfold (_ < 15). ToList to                                                   //> Res11:list[int] = List (one, one, all) +(Frombyunfold (1). Mapbyunfoldinfinite {_ + ten}). Filterbyunfold (_ < 15). ToList -                                                   //> Res12:list[int] = List (one, one, all) the(Frombyunfold (5) Zip Frombyunfold (1). Mapbyunfoldinfinite {_ + ten}). Take (5). ToList *                                                   //> res13:list[(int, int)] = List ((5,11), (6,12), (7,13) , (8,14), (9,15))

Style is basically the same.

After writing these examples, I had time to think about it: what can you do with this infinite data stream? As a data source for database searches, this can be accomplished with a normal stream. Because the infinite data flow is based on some algorithms have regular non-stop to produce data, then used to build a test data source or what mathematical statistical mode of environmental channel is possible. It's also possible to use the game software if you want to keep generating data, so it's OK to draw something dynamic.

Functional Programming (13)-Infinite data stream-infinite stream

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.