如何在scalaz-stream中实现receiveAvailable传感器

时间:2015-07-10 21:26:34

标签: scala scalaz-stream

简短版本:

我想实现一个函数,该函数返回一个等待一个值块发生的传感器"发射"。

我想到的功能将具有以下特征:

/**
 * The `Process1` which awaits the next "effect" to occur and passes all values emitted by
 * this effect to `rcv` to determine the next state.
 */
def receiveBlock[I, O](rcv: Vector[I] => Process1[I,O]): Process1[I,O] = ???

详细信息:

我的理解是我可以使用这个函数来实现以下功能,我觉得这个功能非常有用:

/**
  * Groups inputs into chunks of dynamic size based on the various effects
  * that back emitted values.
  *
  * @example {{{
  * val numberTask = Task.delay(1)
  * val listOfNumbersTask = Task.delay(List(5,6,7))
  * val sample = Process.eval(numberTask) ++ Process(2,3,4) ++ Process.await(listOfNumbersTask)(xs => Process.emitAll(xs))
  * sample.chunkByEffect.runLog.run should be List(Vector(1), Vector(2,3,4), Vector(5,6,7))
  * }}}
  */
  def chunkByEffect[I]: Process1[I, Vector[I]] = {
    receiveBlock(vec => emit(vec) ++ chunkByEffect)
  }

[更新]更多详情

我的最终目标(略微简化)是实现以下功能:

/**
 * Transforms a stream of audio into a stream of text.
 */
voiceRecognition(audio: Process[Task, Byte]): Process[Task, String]

该功能对语音识别服务进行外部呼叫。因此,对流中的每个Byte进行网络调用是不合理的。在进行网络呼叫之前,我需要将字节组合在一起。我可以使audio成为Process[Task, ByteVector],但这需要测试代码才能知道函数支持的最大块大小,我宁愿由函数本身管理。此外,当在服务内部使用此服务时,该服务本身将接收具有给定大小的音频的网络呼叫,我希望chunkXXX功能对于分块是聪明的,这样它就不会保持已经可用的数据。

基本上,来自网络的音频流的格式为Process[Task, ByteVector],并且会被Process[Task, Byte]翻译为flatMap(Process.emitAll(_))。但是,测试代码会直接生成Process[Task, Byte]并将其输入voiceRecognition。从理论上讲,我认为应该有可能给定适当的组合器来提供voiceRecognition的实现,它对这两个流做正确的事情,我认为上面描述的chunkByEffect函数是关键。我现在意识到我需要chunkByEffect函数来使用minmax参数来指定分块的最小和最大大小,而不管产生字节的基础Task

2 个答案:

答案 0 :(得分:1)

你需要以某种方式分离你的字节。我建议在Bytes流上使用更高级别的抽象,即ByteVector。

然后你可能会做手动process1,它的实现与process1.chunkBy类似,只是它在ByteVector上运行。即

def chunkBy(separator:ByteVector): Process1[ByteVector, ByteVector] = {
  def go(acc: ByteVector): Process1[ByteVector, ByteVector] =
    receive1Or[ByteVector,ByteVector](emit(acc)) { i =>
       // implement searching of separator in accumulated + new bytes
       ???
    }
  go(ByteVector.empty)
}

然后这将把所有东西连在一起

val speech: Process[Task,ByteVector] = ???
def chunkByWhatever: Process1[ByteVector,ByteVector] = ??? 
val recognizer: Channel[Task,ByteVector,String] = ???

//this shall do the trick
speech.pipe(chunkByWhatever).through(recognizer)

答案 1 :(得分:0)

我想在这一点上的答案是,gem install cocoapods --pre正确地完成这项工作真的很难或不可能。这个库的新版本被称为mkdir railsbridge ,它具有对“分块”的一流支持,这基本上就是我在这里寻找的。