Scala中此存在类型的正确编码?

Scala中此存在类型的正确编码?,scala,types,stream,scalaz,existential-type,Scala,Types,Stream,Scalaz,Existential Type,我对Coutts等人的流融合论文中的这种流类型编码感兴趣。我正在Scala中探索流融合,试图用宏代替GHC的重写规则 data Stream a = ∃s. Stream (s → Step a s) s data Step a s = Done | Yield a s | Skip s 我尝试了几种不同的方法,但我不确定如何在Scala中对流的类型进行编码,以便两次出现的S都引用相同的类型。我已经很容易地编写了步骤类型 sealed

我对Coutts等人的流融合论文中的这种流类型编码感兴趣。我正在Scala中探索流融合,试图用宏代替GHC的重写规则

data Stream a = ∃s. Stream (s → Step a s) s
data Step a s = Done
              | Yield a s 
              | Skip s
我尝试了几种不同的方法,但我不确定如何在Scala中对流的类型进行编码,以便两次出现的S都引用相同的类型。我已经很容易地编写了步骤类型

sealed abstract class Step[+A, +S]
case object Done extends Step[Nothing, Nothing]
case class Yield[A, S](a: A, s: S) extends Step[A, S]
case class Skip[S](s: S) extends Step[Nothing, S]
到目前为止,这种类型似乎是正确的。我已经使用了协方差,所以类型a=>a的函数将工作,即使我们收到一个收益并返回一个完成或步骤。就像哈斯克尔一样

我的症结一直是Stream的签名。我一直试图将它定义为一个case类。到目前为止唯一有效的签名是使用Exists类型运算符和Tuple来保持两个组件中类型S的相等性,如下所示

type Exists[P[_]] = P[T] forSome { type T }

case class Stream[A](t: Exists[({ type L[S] = (S => Step[A, S], S)})#L])
有没有一种方法可以对它进行编码,这样就不需要元组了?与Haskell(假设存在算子)更接近的是:

其中每个成员可以是单独的字段

我还想到,我可以用SML模块/函子样式对其进行编码,如下所示:

trait Stream[A] {
  type S <: AnyRef
  val f: S => Step[A, S]
  val s: S
}

object Stream {
  def apply[A, S1 <: AnyRef](next: S1 => Step[A, S1], st: S1): Stream[A] = new Stream[A] {
    type S = S1
    val f = next
    val s = st
  }

  def unapply[A](s: Stream[A]): Option[(s.f.type, s.s.type)] = Some(s.f, s.s)
}
trait流[A]{
类型S步骤[A,S]
瓦尔s:s
}
对象流{
def应用[A,S1步骤[A,S1],st:S1):流[A]=新流[A]{
类型S=S1
val f=下一个
val s=st
}
def unapply[A](s:Stream[A]):选项[(s.f.type,s.s.type)]=Some(s.f,s.s)
}
但这有点复杂。我希望有一种更清晰的方法,我不知道。另外,当我尝试探索这条路径时,我不得不做一些事情来满足编译器的要求,例如添加AnyRef绑定,unapply方法不起作用。来自scalac的错误消息:

scala> res2 match { case Stream(next, s) => (next, s) }
<console>:12: error: error during expansion of this match (this is a scalac bug).
The underlying error was: type mismatch;
 found   : Option[(<unapply-selector>.f.type, <unapply-selector>.s.type)]
 required: Option[(s.f.type, s.s.type)]
               res2 match { case Stream(next, s) => (next, s) }
                    ^
scala>res2 match{case Stream(next,s)=>(next,s)}
:12:错误:扩展此匹配时出错(这是scalac错误)。
潜在的错误是:类型不匹配;
找到:选项[(.f.type、.s.type)]
必需:选项[(s.f.type,s.s.type)]
res2 match{case Stream(next,s)=>(next,s)}
^

首先,我觉得
步骤
看起来很完美。至于
,我认为您使用抽象类型是正确的。以下是我的想法(包括Coutts论文第2.1节中剩余方法的实现):

有几件事需要注意:

  • 我的
    unapply
    有一个dependent方法类型:它取决于
    s.s
    。我想这可能是你的绊脚石
  • unstream
    中的
    unfold
    方法不是尾部递归的
我自己还不太清楚的是,
s
的存在性/隐藏性/任何东西为什么重要。如果不是,你可以写:

case class Stream[A, S](next: S => Step[A, S], state: S)

…但我认为这是有原因的。尽管如此,我也不确定这种方法是否真的隐藏了
s
你想要的方式。但这是我的故事,我坚持下去。

对某些{type s}来说
case类流[a](t:(s=>Step[a,s],s)
不起作用吗?@TravisBrown是的,但jroesch正在试图消除元组“unapply selector”bug是。是否有人正在积极研究“unapply selector”bug(我唯一看到的是几个月前Adriaan的分支)?为什么你要在Haskell中放一个存在符号,而这个符号属于一个普遍的符号?我同意抽象类型是最有希望的方法。那么,我将遵循抽象类型成员方法,我仍然对编码存在符号的最佳方法感到困惑。@mergeconflict谢谢你指出我在在依赖类型中,我看到了更清晰的解决方案。此外,隐藏类型是使相同类型的流在不考虑其内部状态/生产者的情况下都是等效的,在这方面我认为它工作得足够好。
abstract class Stream[A] {
  protected type S
  def next: S => Step[A, S]
  def state: S

  def map[B](f: A => B): Stream[B] = {
    val next: S => Step[B, S] = this.next(_) match {
      case Done        => Done
      case Skip(s)     => Skip(s)
      case Yield(a, s) => Yield(f(a), s)
    }
    Stream(next, state)
  }

  def unstream: List[A] = {
    def unfold(s: S): List[A] = next(s) match {
      case Done        => List.empty
      case Skip(s)     => unfold(s)
      case Yield(a, s) => a :: unfold(s)
    }
    unfold(state)
  }
}

object Stream {
  def apply[A, S0](n: S0 => Step[A, S0], s: S0) = new Stream[A] {
    type S = S0
    val next = n
    val state = s
  }

  def apply[A](as: List[A]): Stream[A] = {
    val next: List[A] => Step[A, List[A]] = {
      case a :: as => Yield(a, as)
      case Nil     => Done
    }
    Stream(next, as)
  }

  def unapply[A](s: Stream[A]): Option[(s.S => Step[A, s.S], s.S)] =
    Some((s.next, s.state))
}
case class Stream[A, S](next: S => Step[A, S], state: S)