2013-12-19 25 views
4

我在Haskell中編寫了一個程序,它會生成隨機的三元數整數,以便使用Euterpea作爲和絃播放它們。這裏列出了我的列表清單(顯然,它是無限的,但我會take 10 $ chop 3 $ randInts,其中chop只是一個將列表分成三個(有序)分組的函數,randPitch只是在24-84的間隔內生成整數) :如何過濾一個隨機的Haskell列表,以便每個元素距離下一個距離不超過?

[[27,33,48],[53,59,82],[31,49,62],[50,60,63],[51,56,79],[57,59,60],[52,63,69],[52,77,79],[32,32,37],[39,77,84]] 

要了解一些關於音樂理論,我在申請各種過濾器,這些黑社會。那個給我麻煩的東西(至少在Haskell中這是一種新的語言來實現)是Dmitri Tymoczko稱之爲「合唱旋律符號」 - 即旋律(在這種情況下是頂部'音符'或音高三元組)應該只能移動很短的距離。

我想要做的就是寫一個遞歸濾波黑社會這樣的無休止的列表所導致的是其頂帖僅< = ň移動每個和絃之間黑社會列表的功能:從本質上講,一種隨機行走,你只能移動 n任何一個步驟的半音。以下是我目前使用的功能:

jumpSize :: (Num a, Ord a) => [[a]] -> [[a]] 
jumpSize (_:[]) = [] 
jumpSize (x:y:[]) = (abs (maximum x - maximum y) : x) : [] 
jumpSize (x:y:zs) = (abs (maximum x - maximum y) : x) : jumpSize (y:zs) 

這將預先計算從列表x開頭的三元組x到y的距離。所以take 5 $ jumpSize $ chop 3 $ randPitch給我:

[[34,27,33,48],[20,53,59,82],[1,31,49,62],[16,50,60,63],[19,51,56,79]]  

我試着寫過濾掉所有的弦有很大的跳躍比ñ,重新計算新jumpSizes遞歸函數,然後再次本身完成。但是,我遇到了麻煩,因爲這個功能要麼會導致GHCi崩潰,要麼給我提供各種問題。從結構上講,我想通過對隨機數組進行過濾來產生和絃,但我想我錯過了一些關於如何在功能語言中最好地實現這一點的問題。也許我需要提供一個初始發生器和絃?謝謝!

jumpRecur :: (Num a, Ord a) => a -> [[a]] -> [[a]] 
jumpRecur n (xs) 
    | [x | x <- xs, head x > n] == [] = xs 
    | otherwise     = jumpRecur n $ jumpSize $ filter (\x -> head x <= n) xs 

下面是一個示例輸出:

*Main> jumpRecur 5 $ jumpSize $ chop 3 $ take 1000 $ randPitch 
[[2,2,2,2,2,2,2,2,70,70,76],[1,1,1,1,1,1,1,1,55,74,74],[1,1,1,1,1,1,1,5,26,28,73],   [3,3,3,3,3,3,0,1,26,69,74],[5,5,5,5,5,5,5,5,33,43,77],[0,0,0,0,0,0,0,0,47,67,82],[2,2,2,2,2,2,4,4,37,66,82],[3,3,3,3,3,3,3,3,59,69,84],[4,4,4,4,4,4,4,4,59,79,81],[4,4,5,5,5,5,5,5,28,69,77],[5,5,5,5,5,5,5,5,54,68,73],[0,0,0,0,0,0,0,0,32,73,78],[5,5,5,5,5,5,1,4,52,62,78],[0,0,0,0,0,0,0,0,58,71,73],[3,3,3,3,3,3,4,4,25,64,73],[1,1,1,1,1,3,3,3,35,42,76],[4,4,4,4,4,4,4,4,35,39,77]] 
+1

爲什麼不直接在該範圍內生成隨機數?在每次迭代時,您可以生成一個隨機數randomR(-n,n)gen並將其添加到前一個音符中。 – bheklilr

+0

我的意思是,我正是這樣做的一種命令式語言。我想我喜歡在一些巨大的無限陣列中想象所有可能的和絃,然後不得不將它們濾掉的挑戰。 – todkwxrtvwmzonunswam

+0

如果你可以用命令性語言來做,爲什麼不在Haskell中?儘管如此,處理隨機數字還是有一些注意事項的。我建議使用[MonadRandom](http://hackage.haskell.org/package/MonadRandom)軟件包中的'Rand' monad。我會發佈一個如何使用它的例子。 – bheklilr

回答

3

這是件好事哈斯克爾成語來概括過濾器,如下所示:

jumpBy :: (a -> a -> Bool) -> [a] -> [a] 

jumpBy ok (x:y:zs) | ok x y = x:jumpBy ok (y:zs) -- accept y & step 
        | otherwise = jumpBy ok (x:zs) -- reject y & retry 
jumpBy _ xs = xs 

如果你確信所有的投入將是無限的名單,你並不需要處理有限列表末尾的最後一行,但處理所有情況是一種很好的做法。

然後,用你的普通過濾器與您的特定測試:

jumpSize = jumpBy (\x y -> abs(maximum x - maximum y) < n) 
相關問題