/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

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