在Scala中仅通过代数连续流

时间:2019-01-13 13:13:11

标签: scala scalaz algebra scala-cats

是否可以只用代数定义相同元素的连续流?

如果我查看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,其方式是允许headtail ,但这也可以扩展自身(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的任何想法,这些想法应该是一个元组,同时尝试依靠CatsScalaz中已经存在的东西?

0 个答案:

没有答案