2015-10-20 65 views
7

我想知道是否存在與單子通用的列表中的null等效物或某物。此刻,我試圖找到與== mzero錯誤的值。但是這種檢查會引起誤報,因爲mzero /= Left "foo"適用。Haskell檢查monad中的值是否存在

有沒有一種優雅的方式來表達我想要的標準庫?

+0

看起來好像你的問題在 – Zeta

+0

@Zeta被打斷了是的,我無意中擊中了鍵盤上的返回鍵。 ^^ – bash0r

+1

我認爲所有單子都會出現一些被視爲「錯誤的價值」(我認爲你的意思是某種錯誤/空白情況)的問題 - 你能否提出一些與以前不同的定義/定律那些MonadPlus? – Carsten

回答

12

概念「包含值」不被Monad類型類抓獲。畢竟,一個Monad只給你一些東西順序(>>=)行動(綁定以前的結果)。 MonadPlus爲您提供了一種通過mzero(查看法律和mplus)「快捷」計算的方法。

但是,能夠包含一個或多個值通常與能夠將所有這些值合併爲一些值攜手。事實上,Data.Foldable包含一個函數方便也稱爲null

> import qualified Data.Foldable as F 
> 
> showAndTell :: (Show (t a), Foldable t) => t a -> IO() 
> showAndTell k = 
> putStrLn $ " F.null (" ++ show k ++ ") is " ++ show (F.null k) 

> main = do 
> putStrLn "Using F.null on 'empty' things:" 
> showAndTell $ (Left "Error" :: Either String Int) 
> showAndTell $ (Nothing :: Maybe Integer) 
> showAndTell $ ([]  :: [Double]) 
> 
> putStrLn "" 
> putStrLn "Using F.null on 'filled' things:" 
> showAndTell $ (Right 123 :: Either String Integer) 
> showAndTell $ (Just 123 :: Maybe Integer) 
> showAndTell $ ([1,2,3] :: [Int]) 

結果:

Using F.null on 'empty' things: 
    F.null (Left "Error") is True 
    F.null (Nothing) is True 
    F.null ([]) is True 

Using F.null on 'filled' things: 
    F.null (Right 123) is False 
    F.null (Just 123) is False 
    F.null ([1,2,3]) is False 

所以,你要尋找的是Foldable一部分,而不是Monad。這隻適用於GHC 7.10或更高版本,因爲Data.Foldable.null是基於4.8.0.0版引入的。如果您堅持使用舊版GHC,您可以使用

> isEmpty :: F.Foldable t => t a -> Bool 
> isEmpty = F.foldr (\_ _ -> False) True 
+0

恐怕你不會後向兼容,因爲在GHC 7.10之前'null'並沒有被推廣到'Foldable'。 –

+0

@ØrjanJohansen哎呀。我沒有注意到我在我的GHC 7.10電腦上。 – Zeta

+1

@Zeta別擔心,我也用7.10。感謝您將我指向Foldable類。這正是我要找的。 :) – bash0r

5

我不能當場記住任何簡單的功能,對於所有的單子MaybeEither eMaybeT mExceptT e m,這是我能想到的是有「錯誤值」的主要工作單子。

由於GHC 7.10,null實際上已被推廣(至Foldable),所以它在前兩個工作。

對於最後三個(Either e適用於這兩種方法)及其轉換版本,您可以使用catchError函數。

(雖然最後兩個Foldable情況下,他們的null做錯誤的事情。)

5

絕對不是來自monad外部的。如果你正在尋找像nonEmpty :: MonadPlus m => m a -> Bool那麼這是不可能的。

您需要實際運行單子計算來確定它是否爲「空」。但monad可能需要某種輸入來運行(例如State或甚至Reader),並且在極端情況下爲IO,您無法從外部運行monad。現在這些例子不是MonadPlus在他們自己的AFAICR,但增加他們的失敗(例如MaybeT),突然有一個明確的定義是什麼意思,他們是「空的」,但仍然適用相同的限制。由於未知的monad可能是其中之一,因此無法獲取任何信息。

可能的簽名可能是nonEmpty :: MonadPlus m => m a -> m Bool(儘管我不確定它是否具有合理的實現)。但我不認爲這就是你以後的事情,因爲它實際上並不推廣null;你最終會退出[False][True]列表(或可能甚至[True, True, True, ...]與輸入元素數相同),這有點奇怪。

我認爲單子在錯誤的「泛化軸」上是null;你需要一個比Monad更好地表徵容器的抽象(許多單子容器,但很多其他東西都非常不同,所以在任意monads上工作的代碼不能假定容器類屬性)。在GHC-7.10中發生的Foladable似乎是一個相當不錯的選擇。你或許可以製作一個CanBeEmpty類型的類,它允許比Foldable承認更多的東西;我不知道這樣的事情已經存在了。

+0

'可摺疊'完全夠用了。我不知道null是否已經被GHC 7.10推廣了,如果有足夠的類型類,我不想實現類似'Foldable'的東西。 – bash0r

2

要做的地道的事情不是試圖直接檢測零點,而是提供你想要的行爲,以防零。

這是什麼mplus或等效(在最近的前奏)<|>做;它會在第一個操作失敗的情況下鏈接一個操作來運行。這與catchError支持的Monads上的catchError相同。它類似於shell或perl編程中常見的成語foo || bar,意思是運行foo,然後在foo失敗時運行欄。

請注意,在列表monad中它將運行所有選項,但因爲這是列表monad設計工作的原因,所以建模'多種可能性'。

我經常使用<|>MaybeTEitherT建模左偏向選擇,即「依次嘗試所有這些選擇,直到一個成功」。

請注意,使用<|>代替EitherT確實會丟棄錯誤消息(因爲它將失敗的計算轉換爲後續計算);如果你想保存錯誤信息並以某種方式處理它,那就是你想要的catchError