Functional Programming (36)-Functional stream Io:io Data source-io Source & Sink

Source: Internet
Author: User

In the previous period we discussed the IO processing process: process[i,o]. We say process is like a TV signal box with both input and output ends. The process can be connected to the input of another process with the output of one process to form a sequence of complete IO processes with multiple data processing functions. However, the two inputs of the synthetic IO process need to be connected to a data source, while the other end may receive a data receiving device such as a file, a display, etc. In this article, we briefly introduce the IO data source and IO data receiver sink.

We first use a separate data type to represent the source of the data in a simple demonstration, which has no relation to the process type:

Import processlib._object Sourcesink {trait source[o] {  //The following helper function is to treat Source as a list of O class  def |>[o2] (P:process[o,o2]): Source[o2]   //Glue a Process p to it input O  def filter (f:o = Boolean): source[o] = this |> proce Ss.filter (f)//to P input O  def map[o2] (f:o = O2): Source[o2] = this |> process.lift (f)  def take (n:int): source[ O] = this |> process.take (n)  //intercept the first n O  def takewhile (f:o = = Boolean): source[o] = this |> process.takewhi Le (f)  def drop (n:int): source[o] = this |> process.drop (n)//Skip Top n O  def dropwhile (f:o = Boolean): source[ O] = this |> process.dropwhile (f)}

as you can see from the above trait: source works by pasting the input of a process into the output of source. We can use this |> to glue a bunch of process to the output of the source, such as: SRC.PROC1.PROC2.PROC3. But first we have to define PROC1,PROC2,PROC3 as the source component function, because source is a completely independent type.

Let's take a look at a source special case:

Case Class Resourcer[r,i,o] (   A read-only resource for//source Acquire:io[r],   //Resource Usage Portal  resource handle release:r = IO [Unit],//Finish using resource cleanup function step:r = Io[option[i]],//resource content read function Trans:process[i,o]//  output mode) extends Source[o] {def |& Gt [O2] (P:process[o,o2]): source[o2] =  //Implement abstract function   resourcer (Acquire,release,step,trans |> p)// Each input produces a resourcer. Its trans and P pipe docking}

This is a read-only data source. We see that all of the actions are embedded in the IO type, which can delay the generation of side effects to some source interpreter. Here we can just use the simplest IO to illustrate:

Trait Io[a] {self =    def run:a    def map[b] (f:a = B): io[b] =      new Io[b] {def run = f (self.run)}    def flatmap[b] (f:a = io[b]): io[b] =      new Io[b] {def run = f (self.run). Run}}object IO {    def unit[a] (A: = = A): io[a] = new Io[a] {def run = A}    def Flatmap[a,b] (Fa:io[a]) (f:a = io[b]) = FA flatMap F    def Apply[a] (A : = = a): io[a] = unit (a)//syntax for IO {.}}

This IO type has been practiced in previous discussions.

Now let's take a look at the resourcer example of a file read:

Object Source {Import java.io._def lines (filename:string): source[string] =  //read String from file filename  resourcer (   //Create an instance of source    io {io). Source.fromfile (FileName)},  //Resource    (Src:io. Source) = = IO {src.close},  //Cleanup    (Src:io.  Source) = = IO {    //Read    lazy val iterator = Src.getlines    if (iterator.hasnext) Some (iterator.next) Else None Read back to None    },    process.passunchanged)//process[i,i], read what enter what}

Now we can write a program like this:

Source.lines ("Input.txt"). Count.exists{_ >= 40000}                                                  //> res0:ch15. Sourcesink.source[boolean] = Resourcer (ch15. sourcesink$io$ $anon $                                                  //| [Email protected],<function1>,<function1>,await (<function1>)]

Oh, remember to put count and exists in source trait:

def exists (f:o = Boolean): Source[boolean] = this |> process.exists (f) def count:source[int] = this |> Process. Count

The above expression can be described as just the description of the IO process. The actual side effects are generated in the interpreter:

def Collect:io[indexedseq[o]] = {  //Read data source return Io[indexedseq[o]], use Io.run to actually operate Def Tryor[a] (A: = a) (cleanup:io[ Unit]): a =  //Operation expression A, an exception immediately clears the field   try A catch {case e:exception = Cleanup.run; throw e} @annotation. tailrec
   //This is a tail recursion algorithm, according to Trans State def go (Acc:indexedseq[o], Cleanup:io[unit], step:io[option[i], Trans:process[i,o]): Indexedseq[o] =   Trans Match {case   Halt () = Cleanup.run; ACC  //Stop State, clear field case   Emit (out,next) = Go (Tryor (out +: ACC) (cleanup), cleanup, step, next)//accumulate ACC case   Await (iproc) = Tryor (Step.run) (cleanup) match { C9/>case None = Cleanup.run; ACC  //Finish cleaning up the scene case   si = Go (Acc,cleanup,step,iproc (SI))  //read into the element as process input to change the process state   }   } Acquire map {res = go (Indexedseq (), Release (RES), step (res), trans)}//Start reading}

Note: The on-site cleanup will prevent resources from leaking, regardless of the read completion or the Midway failure exit. It can be inferred that the interpreter is still safe.

As with source, we use a separate type of sink to represent the data receiving side for a brief explanation:

Trait Sink[i] {def <|[ I2] (P:process[i2,i]): Sink[i2]//p output to Sink input def filter (f:i = Boolean): sink[i] = this <| Process.filter (f)  //Receive I def from P map[i2] (f:i2 = i): sink[i2] = this <| Process.lift (f)//convert received I2 into I def take (n:int): sink[i] = this <| Process.take (n)  //Receive First n I def takewhile (f:i = Boolean) from P: sink[i] = this <| Process.takewhile (f) def drop (N:int): sink[i] = this <| Process.drop (n)//filter out first n I def dropwhile (f:i = Boolean): sink[i] = this <| Process.dropwhile (f)}

This is similar to source trait. Note that the process connection is reversed: the P points to the sink.

Similarly, a write-only resource instance is as follows:

Case Class Resourcew[r,i,i2] (  //write-only resource   acquire:io[r],   //Resource Usage portal, resource handle   release:r = io[ Unit],  //cleanup function   rcvf:r = (I2 = Io[unit]),//Receive mode   TRANS:PROCESS[I,I2]  //process   ) extends sink[ I] {   def <|[ I2] (P:process[i2,i]): sink[i2] =     resourcew (acquire,release,rcvf,p |> Trans)//Manufacturing a Resourcew instance, from p to trans   }

This is similar to Resourcer. Or is connected to the process in the opposite direction: from P to trans.

The following is a sink component that writes to a file:

Object Sink {Import java.io._ def file (filename:string, Append:boolean = False): sink[string] =//result is sink[string]. You must use interpreter to calculate   resourcew (   //is a Resourcew instance   IO {new FileWriter (filename,append)},//Create FileWriter   (w:filewriter) = io {w.close},  //Release FileWriter   (w:filewriter) = (s:string) + = io {w.write (s)},< c6/>//Write   process.passunchanged    //write Data not processed   )}

During the learning process, it is found that the Source,sink type independent of the process type makes integration of the expression types of the IO algorithm difficult. This also limits the functionality of the component. We cannot realize the simple and elegant expression of functional programming. In the following discussion, we will focus on analyzing the process of having a data source function, hoping to improve the way we express ourselves.










Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Functional Programming (36)-Functional stream Io:io Data source-io Source & Sink

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.