2017-08-04 42 views
1

我正在尝试处理音频信号的通道。我得到信号作为帧的列表,其中每个帧具有每个通道的样本。现在我想独立处理这些流,然后再合并它们。所以,我想写清单解复用器

type Sample = Double 
type Frame = [Sample] 
type Stream = [Sample] 
mux :: [Stream] -> [Frame] 
demux :: [Frame] -> [Stream] 
process :: Stream -> Stream 

output = (mux . (map process) . demux) input 

mux [[0.1, -0.1, -0.3], [0.2, 0.4, 0.6]] = [[0.1, 0.2], [-0.1, 0.4], [-0.3, 0.6]] 
demux [[0.1, 0.2], [-0.1, 0.4], [-0.3, 0.6]] = [[0.1, -0.1, -0.3], [0.2, 0.4, 0.6]] 

由于流长,muxdemux必须偷懒,不评估整个列表。

复用器看起来很简单。我不喜欢这个版本的唯一的东西是难以阅读的模式匹配。

mux [email protected]((_:_):_) = map head streams : mux (map tail streams) 
mux _ = [] 

但是,我不能轻易想出一个多路解复用器,将帧的列表转换为流的列表。因为在我的情况下,不会有两个以上的流(立体声音频),我想我可以通过编写两个分路器monoDemuxstereoDemux来管理。但我希望有一个功能可以处理任意数量的频道。我怎样才能懒散地解组帧列表?

回答

5

我认为工作已经为你做了:既muxdemux,实际上只是transpose :: [[a]] -> [[a]]功能:

import Data.List(transpose) 

mux = transpose 
demux = transpose 

因此,这意味着复用实际上是(至少在列表清单的方面)与解复用相同。

它产生预期:

Prelude Data.List> transpose [[0.1, -0.1, -0.3], [0.2, 0.4, 0.6]] 
[[0.1,0.2],[-0.1,0.4],[-0.3,0.6]] 
Prelude Data.List> transpose [[0.1, 0.2], [-0.1, 0.4], [-0.3, 0.6]] 
[[0.1,-0.1,-0.3],[0.2,0.4,0.6]] 

transpose作品在一个慵懒的方式。我们可以检查source code

transpose    :: [[a]] -> [[a]] 
transpose []    = [] 
transpose ([] : xss) = transpose xss 
transpose ((x:xs) : xss) = (x : [h | (h:_) <- xss]) : transpose (xs : [ t | (_:t) <- xss]) 

最后一条语句是一个复杂的版本:

transpose l = map head l : transpose (map tail l) 
+1

漂亮,我从来没有见过复用这种方式!即使我自己的功能是双向的,我没有注意到。 (而且我仍然不明白为什么,必须在纸上写出来。) – sba

+2

这个定义是否意味着'转置'是一个部分函数?我的意思是,如果我说'转置[[1],[]]',它会破裂,对吧? –

+1

@FyodorSoikin:不,如文档所述:“*如果某些行比下列行短,则会跳过它们的元素:*”。给定的定义确实是错误的,但显然源代码已经更新。 'transpose [[1],[]]'产生'[[1]]'。 –