0

Would it be possible to define a continuous stream of the same element with just algebra?

If I look at the implementation of Streams in Scala I see the following method definition:

def continually[A](elem: => A): Stream[A] = cons(elem, continually(elem))

Look at Cons you can see that it's just a tuple with a head element and a tail.

final class Cons[+A](hd: A, tl: => Stream[A]) extends Stream[A]

I'm having difficulties of creating this Cons class with just algebra.

def continually[A, G[_]](a: => A): G[A] = {
  ???
}

The above is not enough, because I need a different type, let's call it B that represents Cons in a way that it allows a head and a tail, but that also extends itself (Stream or in this case G[_]).

def continually[A, G[_], B <: G](a: => A): B = {
  ???
}

My first naive implementation is as follows:

def continually[A, G[_], B <: G[A]](a: => A)
                                   (implicit pureB: (A, G[A]) => B): B = {
  pureB(a, continually[A, G, B](a))
}

// Run
implicit def pureStream[A](head: A, tail: Stream[A]) = cons(head, tail)
continually[Int, Stream, Cons[Int]](1)

But this is of course not lazy.

My second attempt is making the tail lazy and it works as expected:

def continually[A, G[_], B <: G[A]](a: => A)
                                   (implicit pureB: (A, => G[A]) => B): B = {
  println("[continually called]")
  pureB(a, continually[A, G, B](a))
}

implicit def pureStream[A](head: A, tail: => Stream[A]) = cons(head, tail)

val result = Source
  .fromIterator(() => continually[Int, Stream, Cons[Int]](1).toIterator)
  .throttle(1, 1.second)
  .runWith(Sink.foreach(println))

result.onComplete(_ => println("*** Finished ***"))

Which results in the output below:

[continually called]
[continually called]
1
[continually called]
1
[continually called]
1
[continually called]
1
[continually called]
1
[continually called]
1
[continually called]
1
[continually called]
1
[continually called]
1

So my question now is as follows:

Instead of explicitly asking for a implicit pureB: (A, => G[A]) => B, is there any other way to ask for an applicative that can instantiate a tuple? I can't use implicit applicativeB: Applicative[B], because B is not aware that is supposed to be a tuple with a lazy tail.

My idea was to create a new type definition for B where it is now aware that it is a tuple with a lazy tail.

B <: (A, => G[A]): G[A]

However this is now allowed by the compiler:

Error:(77, 39) no by-name parameter type allowed here
    def continually[A, G[_], B <: (A, => G[A]): G[A]](a: => A)

Any idea on how I can create something of B that is supposed to be a tuple and at the same time trying to lean on stuff that is already there in Cats or Scalaz?

Anton
  • 27
  • 1
  • 4
  • Are you looking for something like `Stream.continually(1)` or `lazy val stream: Stream[Int] = 1 #:: stream`? Both create a lazy, infinite stream containing only that one element. – Aki Jan 13 '19 at 13:26
  • I'm aware of the `Stream.continually`. My question is not about "how to create an infinite stream of Integers", but "how would I define an algebra that makes this possible, without relying on concrete types". – Anton Jan 13 '19 at 14:42
  • In Scala terminology, `Cons` is not a `Tuple`. As for your last definition of `B`, I think you need to use `=>`: `B <: (A, => G[A]) => G[A]` compiles for me. – Brian McCutchon Jan 13 '19 at 18:43

0 Answers0