2017-08-04 43 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]]'。 –