2016-01-25 60 views
2

我正在研究Project Euler的問題9,並且我有一個關於在另一個monad中提取可能值的最佳方法的問題。該問題詢問找到 'A', 'B', 'C' 滿足:Haskell - 提取可能在Monad中

  • 一個^ 2 + B^2 = C^2
  • A + B + C = 1000

我寫了下面的代碼解決了這個問題:

problem9 :: (Integral a) => a -> [(a, a, a)] 
problem9 n = 
    do 
     a <- [1..n] 
     b <- [1..a] 
     c <- fromJustM (findC a b) 
     guard (a + b + c == n) 
     return (a, b, c) 

「C」可以分析計算,但是,因爲它可能不存在,我返回一個值可能。

findC :: (Integral a) => a -> a -> Maybe a 
findC a b = ... (implementation) ... 

要提取列表單子裏面也許值,我創建了以下功能:

fromJustM :: (Monad m) => Maybe a -> m a 
fromJustM (Just a) = return a 
fromJustM Nothing = fail "" 

看起來這應該是一個常見的操作,所以是有一個標準庫函數,它這,還是有一種更習慣的方式來做到這一點?

+0

爲什麼不給'findC'一個更多的多態類型(例如,按照這裏回答的建議'(Alternative f,Integral a)=> a - > a - > f a')? –

回答

6

fail實際上並不是單子操作;它僅在Monad類型類中因爲歷史意外/隱藏了一些髒錯誤處理。

這個更合適的類別是MonadPlus,或者更確切地說是Applicative記者Alternativefail轉換爲empty。就這樣,你的簽名其實應該

fromJustM' :: Alternative m => Maybe a -> m a 

Hoogle offers

asum :: (Foldable t, Alternative f) => t (f a) -> f a 

符合該法案:MaybeFoldable

 c <- asum $ pure <$> findC a b 

可以說,這實際上並不是可讀的。


實際上,你可以實現你的目標多寫

 Just c <- pure $ findC a b 

這並再次使用fail方法更簡單:在do塊模式匹配失敗調用它含蓄。