簡體   English   中英

過濾申請人

[英]Filtering Applicatives

我正在做NICTA Haskell課程並且堅持使用Applicative的最后一部分,這是我的進步。

基本上,我們將使用在Applicative上下文中生成List的謂詞來過濾List。

filtering :: Applicative f => (a -> f Bool) -> List a -> f (List a)
filtering _ Nil = pure Nil
filtering f (x :. rest) = 
        let whole = lift2 (:.) (pure x) (filtering f rest) in
        lift2 filter (const <$> f x) whole

所以whole這里是完整的未過濾列表,所以我解除了一個filter ,並且(const <$> fx)添加的const是滿足filter(a -> Bool)要求。

一切都很好,它編譯成功,但它失敗了一個測試用例,所以這里肯定是錯的。

例如, filtering (Id . even) [4,5,6]只返回Id [4]而不是Id [4,6] (Id只是一個容器而且是一個Applicative。)

我在某個地方犯了什么錯誤嗎?

這里的問題是(const <$> fx) 該函數將用於檢查整個列表,但它只會在當前x上提供f的結果。 這意味着當它在[5,6]子列表上工作時,它基本上是filter (const False) [5,6] ,這會產生一個空列表。

您無法調用filter為您執行此操作,因為它的形狀不正確。 這樣的事總會發生。 相反,只需專注於包含當前元素,並讓遞歸正確處理列表的其余部分。 (我不想多說,因為這個課程的目標當然是為自己解決這個問題。)

我對你認為需要“完整的未經過濾的清單”感到困惑,我想你也是。 完整的未過濾列表x :. rest x :. rest ,你已經擁有了!

顯然,你的意思是“整個的結果,因為這將是如果斷言總是得到True ...但是,這沒有任何意義,因為你基本預測,這始終產生True

您需要考慮的是,而不是whole事情,是兩個應用程序包裝的值:頭部謂詞的結果 - 這只是fx :: f Bool 並且,作為遞歸, 過濾剩余的列表filtering f rest :: f (List a)

現在,正如您已經注意到, liftA2通常是組合兩個Applicative -wrapped值的最簡單方法(盡管<*>實際上傾向於為更整潔的代碼提供)。 召回

liftA2 :: (a->b->c) -> f a -> f b -> f c

在這種情況下,

liftA2 :: (Bool->List a->List a) -> f Bool -> f (List a) -> f (List a)

因此,您需要一個函數Bool->List a->List a ,如果布爾值為true,則前綴為x ,否則保留列表。 好吧,在本地where塊中定義它應該不是問題。

這個問題要簡單得多,如果不是在一個函數中嘗試它,而是將它分解為更小的子問題。

我給出的第一個提示是它看起來非常像Traversable類的一個問題,其中包括這個方法,它的簽名應該讓你“嗯!”:

traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)

通過您問題中的搞笑List類型,我收集您正在采取的課程,不允許使用庫函數來解決問題。 我不太同意這種做法; 我認為最好的學習方法是以下兩步過程:

  1. 使用庫函數解決問題。 通過這種方式,您可以學習庫,更重要的是,您將學習如何將問題分解為更小,更通用的庫。
  2. 編寫您自己的庫函數版本。 通過這種方式,您可以了解基於庫的解決方案的工作原理。

所以我建議作為一個子問題,你應該為你的List類型編寫自己的Traverse版本。

下一個子問題:使用traverse ,編寫此函數應該很簡單:

tagWithBool :: (a -> f Bool) -> -> List a -> f (List (Bool, a))

一旦你有了這個,我要做的下一步就是編寫這個函數:

-- Remove the items tagged with `False`, and eliminate the tags.
removeFalse :: List (Bool, a) -> List a

同樣,我建議您在編寫時充分利用mapfilter等實用程序功能,並在正確運行后,編寫自己的函數版本作為額外練習。 (實際上,考慮到問題中的非標准List類型,你幾乎不得不編寫自己的版本來解決這個問題。)

一旦掌握了所有這些,您就可以寫:

filtering :: Applicative f => (a -> f Bool) -> List a -> f (List a)
filtering p xs = fmap removeFalse (tagWithBool xs)

請注意,這使用fmap ,因此您必須為List類型實現Functor (或者只是mapList :: (a -> b) -> List a -> List b函數)。

這個怎么樣(我正在使用普通列表,而不是你的ctor)

seq f [] = []
seq x:xs = lift2 (:) x (seq xs)
remove (x:xs) (y:ys) = (if y then [x] else []) ++ remove xs ys

filterapp f xs = lift2 remove (pure xs) $ seq $ map f xs 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM