我想撰寫一個函式來列印所有排序的子序列和另一個條件。
我已經實作了一個函式,它顯示所有排序的子序列,如下所示:
allSubseqs:: Ord a => [a] -> [[a]]
allSubseqs = filter' isSorted . subsequences
我想做進一步的過濾器以僅選擇具有最大長度的串列。我知道如何使用 let,但我想直接將其添加到 allSubseqs 函式中:
這是代碼的結果,它是正確的:
[[3,5,7,8],[1,5,7,8],[1,2,7,8]]
uj5u.com熱心網友回復:
好吧,其中一個let可以直接關閉;你let x2 = x1并沒有真正做太多,我們可以在任何地方x2替換x1。
main :: IO ()
main = do
let x1 = allSubseqs2 [6,3,1,5,2,7,8,1]
print $ filter' ((==) (maximum (map' length x1)) . length) x1
從技術上講,我們也可以用 替換所有出現的x1地方allSubseqs2 [...],但不幸的是,這會計算兩次子序列。所以let必須留下來。
盡管如此,如果需要的話,我們可以分解出對allSubseqs2and的呼叫filter',將它們組合在一個函式中。它看起來幾乎相同,只是替換print為......什么都沒有!
longSubseqs values = do
let x1 = allSubseqs2 values
filter' ((==) (maximum (map' length x1)) . length) x1
實際上,這有點欺騙性。大多數 Haskeller 會期望看到一個do塊時會發生一些單子的事情,而這里沒有任何這樣的事情發生。讓我們將do/更改let為let/ in:
longSubseqs values = let x1 = allSubseqs2 values in
filter' ((==) (maximum (map' length x1)) . length) x1
使用任一定義,我們現在可以撰寫更短的main:
main = print $ longSubseqs [6,3,1,5,2,7,8,1]
-- OR
main = do
print $ longSubseqs [6,3,1,5,2,7,8,1]
uj5u.com熱心網友回復:
聽起來您正在嘗試使您的功能無點。也就是說,您希望將所有過濾器和串列操作定義為一系列函式應用程式,而不是使用變數和 let 系結。這當然是可行的!
我喜歡的一種很好的解決方法是使用箭頭組合器而不是(.),因為它允許定義從左到右的函式管道,而不是典型的(數學)從右到左的組合。我們將從匯入開始:
import Control.Arrow ((>>>), (&&&))
運算子只是翻轉組合,>>>我們稍后再討論&&&。
現在,讓我們把你的allSubseqs函式寫成這種箭頭樣式:
allSubseqs:: Ord a => [a] -> [[a]]
allSubseqs = subsequences >>> filter' isSorted
接下來,我們要做另一個過濾,這次是在串列的長度上,但我們還需要知道串列的最大長度。通常,這是使用 let 陳述句或變數系結(就像您所做的那樣)的地方,但是,我們可以使用&&&. 組合器&&&接受兩個函式,每個函式接受相同的輸入,并產生一對函式的輸出。我們可以使用它來代替類似的let東西:
allSubseqsAndLongestLength :: Ord a => [a] -> (Int, [[a]])
allSubseqsAndLongestLength = subsequences
>>> filter' isSorted
>>> (maximum . map' length) &&& id
到目前為止的輸出現在是一對已排序子序列的最大長度以及所有已排序子序列的串列。是時候將它輸送到最終過濾器中了:
allLongestSubseqs :: Ord a => [a] -> [[a]]
allLongestSubseqs = subsequences
>>> filter' isSorted
>>> (maximum . map' length) &&& id
>>> uncurry (filter' . (. length) . (==))
我們本可以將最后一行寫成>>> (\(maxLen, lst) -> filter' ((== maxLen) . length) lst),但我冒昧地讓它像函式的其余部分一樣無點。
你有它!您甚至可以根據filter需要添加更多 s 或其他串列操作,只需將它們組合到鏈的末尾即可。
uj5u.com熱心網友回復:
使用DDub的答案中的“裝飾-程序-不裝飾”范式(又名Schwartzian 變換)可以讓您在準備好要處理的資料后,在鏈中添加額外的過濾器。
但是最好完全避免第二個過濾器,首先按順序生成子串列,最長的 first,然后只取 head 元素:
longestSorted :: Ord a => [a] -> [[a]]
longestSorted = rpowers >>>
map (filter isSorted) >>>
dropWhile null >>>
concat . take 1
-- > longestSorted [1,4,3,5]
-- [[1,4,5],[1,3,5]]
這使用rpowers了這個答案:
-- longest first:
rpowers :: [a] -> [ [[a]]]
rpowers [] = [ [[]] ]
rpowers (x:xs) =
[ map (x:) b a | (a:b:_) <- tails ([[]] rpowers xs) ]
[ [[]] ]
-- shortest first, for comparison:
powers :: [a] -> [ [[a]]]
powers [] = [ [[]] ]
powers (x:xs) = [ [[]] ]
[ map (x:) a b | (a:b:_) <- tails (powers xs [[]]) ]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/462843.html
上一篇:如何從源代碼構建llvm-hs
