是否可以只用代数定义相同元素的连续流?
如果我查看Scala中Streams的实现,则会看到以下方法定义:
def continually[A](elem: => A): Stream[A] = cons(elem, continually(elem))
看看Cons
,您会发现它只是一个带有head元素和一个tail元素的元组。
final class Cons[+A](hd: A, tl: => Stream[A]) extends Stream[A]
我很难用代数创建这个Cons
类。
def continually[A, G[_]](a: => A): G[A] = {
???
}
以上内容还不够,因为我需要使用其他类型,因此我们将其称为B
来表示Cons
,其方式是允许head
和tail
,但这也可以扩展自身(Stream
或本例中的G[_]
)。
def continually[A, G[_], B <: G](a: => A): B = {
???
}
我的第一个天真的实现如下:
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)
但这当然不是偷懒。
我的第二次尝试是使尾巴变懒,并且按预期方式工作:
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 ***"))
这将导致以下输出:
[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
所以我的问题如下:
除了显式地请求implicit pureB: (A, => G[A]) => B
之外,还有其他方法可以请求可实例化元组的应用程序吗?我不能使用implicit applicativeB: Applicative[B]
,因为B不知道那应该是一个带有懒尾的元组。
我的想法是为B
创建一个新的类型定义,现在它知道它是一个带有懒尾的元组。
B <: (A, => G[A]): G[A]
但是编译器现在允许这样做:
Error:(77, 39) no by-name parameter type allowed here
def continually[A, G[_], B <: (A, => G[A]): G[A]](a: => A)
关于如何创建B
的任何想法,这些想法应该是一个元组,同时尝试依靠Cats
或Scalaz
中已经存在的东西?