PageRenderTime 23ms CodeModel.GetById 17ms app.highlight 3ms RepoModel.GetById 2ms app.codeStats 0ms

/example/src/main/scala/scalaz/example/WordCount.scala

http://github.com/scalaz/scalaz
Scala | 48 lines | 24 code | 12 blank | 12 comment | 3 complexity | cf2c02192ff0063f9c4a890b722154f7 MD5 | raw file
 1package scalaz.example
 2
 3import scalaz.{Monoid, StateT}
 4
 5
 6/**
 7 * Character/Line/Word Count from "The Essence of the Iterator Pattern".
 8 *
 9 * @see [[http://www.comlab.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf]]
10 */
11object WordCount {
12  def main(args: Array[String]) = {
13    wordCount
14  }
15
16  def wordCount(): Unit = {
17    import scalaz.State
18
19    val text = "the cat in the hat\n sat on the mat\n".toList
20
21    import scalaz.std.anyVal._, scalaz.std.list._, scalaz.std.boolean.test
22
23    // To count words, we need to detect transitions from whitespace to non-whitespace.
24    // atWordStart_{i} = heaviside( test(isSpace(c_{i}) - test(isSpace(c_{i-1})) )
25    def atWordStart(c: Char): State[Boolean, Int] = State { (prev: Boolean) =>
26      val cur = c != ' '
27      (cur, test(cur && !prev))
28    }
29
30    // To count, we traverse with a function returning 0 or 1, and sum the results
31    // with Monoid[Int], packaged in a constant monoidal applicative functor.
32    val Count = Monoid[Int].applicative
33
34    // Compose the applicative instance for [a]State[Boolean,a] with the Count applicative
35    val WordCount = StateT.stateMonad[Boolean].compose[λ[α=>Int]](Count)
36
37    // Fuse the three applicatives together in parallel...
38    val A = Count
39      .product[λ[α=>Int]](Count)
40      .product[λ[α=>State[Boolean,Int]]](WordCount)
41
42    // ... and execute them in a single traversal
43    val ((charCount, lineCount), wordCountState) = A.traverse(text)((c: Char) => ((1, test(c == '\n')), atWordStart(c)))
44    val wordCount = wordCountState.eval(false)
45
46    println("%d\t%d\t%d\t".format(lineCount, wordCount, charCount)) // 2	9	35
47  }
48}