enumerator composition - 2 sources to one sink, can someone translate haskell to scala?

185 views
Skip to first unread message

Zbigniew Szymanski

unread,
Apr 27, 2013, 4:07:10 AM4/27/13
to play-fr...@googlegroups.com
Hi,

I need to read two enumerators simultaneously and advance one stream based on results from the other.
This seems to be nicely described for haskell here: http://okmij.org/ftp/Streams.html#2enum1iter

Can someone show me how to do this using play enumerators?

How would this example look like in scala?:
i1 :: Monad m => Iteratee el1 (Iteratee el2 m) (el1, el2)
     i1
= do
          e1
<- head
          e2
<- lift head
         
return (e1,e2)


Rich Dougherty

unread,
Apr 28, 2013, 7:09:44 AM4/28/13
to play-fr...@googlegroups.com
I had a go, but I'm not sure this it's right. What do you think?

  def i1[E] = for {
    e1 <- Iteratee.head[E];
    e2 <- Iteratee.head[E]
  } yield (e1, e2)

Cheers
Rich



--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Zbigniew Szymanski

unread,
Apr 28, 2013, 9:44:10 AM4/28/13
to play-fr...@googlegroups.com
This isn't what I need, your solution would just read 2 sequential elements from one Enumerator, and there is no way to even apply it to the second one (enumerators could possibly have different types)

I don't know if this is even possible with Play enumerators, so maybe I'm just asking wrong question. 

Raul Raja Martinez

unread,
Apr 28, 2013, 9:57:17 AM4/28/13
to play-fr...@googlegroups.com
I may not completely understand the question but there is a "interleave" ">-" method on the Play Enumerator that combines the input on two enumerator to the resulting interleaved enumerator.

--
--
Raúl Raja Martínez
Co-founder @ 47 Degrees

Zbigniew Szymanski

unread,
Apr 28, 2013, 12:00:00 PM4/28/13
to play-fr...@googlegroups.com
Interleave returns elements in no specific order, it just returns the first available one.
The haskel solution gives us control on the resulting ordering, we can block one enumerator while waiting on results from the other. The example that I pasted returns a pair of first elements from two enumerators, and no other element is  ever read, this even works with enumerators producing elements with different speed (consider one producing element from memory and the other making internet connection)
There is also some more complicated example where you read one element from first enumerator and then based on returned value you decide how many elements you need to read from the second one (without advancing the first one)

One especially useful application of this (the one that I need) would be to merge two sorted streams maintaining correct order.

Rich Dougherty

unread,
Apr 28, 2013, 4:30:49 PM4/28/13
to play-fr...@googlegroups.com
Yes it will be possible to construct what you're after—whether or not my answers are actually correct. :)

In my first example I flatMapped when I should have mapped. My Haskell to Scala translation skills are rather weak, having never programmed in Haskell.

  def i1[E1,E2]: Iteratee[E1, Iteratee[E2, (Option[E1], Option[E2])]] = {
    Iteratee.head[E1].map(e1 => Iteratee.head[E2].map(e2 => (e1, e2)))
  }

Example usage:

  val i1 = Iteratee.i1[Int, String]
  val res = (Enumerator(1, 2, 3, 4) |>>> i1).flatMap(i2 => Enumerator("5", "6", "7", "8") |>>> i2)
  Await.result(res, Duration.Inf) must equalTo((Some(1), Some("5")))

One of the differences is that Play's iteratees are asynchronous and make extensive use of futures. The |>>> operation returns its result in a future so we need to flatMap the result of the first iteration together with the second. We also need to await the result of the second iteration at the end.

Cheers
Rich

Zbigniew Szymanski

unread,
Apr 29, 2013, 1:18:32 AM4/29/13
to play-fr...@googlegroups.com
Thanks, that works fine. 
(for some reason I thought this would be more complicated)

Now I need to apply it to merging:

Rich Dougherty

unread,
Apr 30, 2013, 3:55:17 AM4/30/13
to play-fr...@googlegroups.com
On Mon, Apr 29, 2013 at 5:18 PM, Zbigniew Szymanski <zbig...@gmail.com> wrote:
Thanks, that works fine. 
(for some reason I thought this would be more complicated)

Now I need to apply it to merging:

You're welcome! Good luck with the merge implementation. :)

Cheers
Rich 

Thomas Beckmann

unread,
Dec 22, 2013, 10:35:33 AM12/22/13
to play-fr...@googlegroups.com
I'm also searching for an implementation of merge but had no luck except this thread. I don't have any haskell background and the Iteratee concept is new to me.
Could anybody give some more details or provide another example since the above code doesn't compile for me and I don't know how to fix it.

Rich Dougherty

unread,
Feb 1, 2014, 4:41:47 AM2/1/14
to play-fr...@googlegroups.com
On Mon, Dec 23, 2013 at 4:35 AM, Thomas Beckmann <beckmann.t...@gmail.com> wrote:
I'm also searching for an implementation of merge but had no luck except this thread. I don't have any haskell background and the Iteratee concept is new to me.
Could anybody give some more details or provide another example since the above code doesn't compile for me and I don't know how to fix it.

What code are you using and what compile errors are you getting?

- Rich

-- 
Rich Dougherty - @richdougherty
Typesafe - Reactive apps on the JVM
Reply all
Reply to author
Forward
0 new messages