2016-01-25 2 views
2

Я работаю над проблемой 9 Project Euler, и у меня есть вопрос о том, как лучше извлечь значение внутри другой монады. Проблема просит найти 'а', 'B', 'C', которые удовлетворяют:Haskell - Extract Возможно, в Монаде

  • а^2 + Ь^2 = с^2
  • а + Ь + с = 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) 

«с» может быть вычислена аналитически, но, так как он не может существовать, я, может быть, возвращающий значение.

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' более полиморфный тип (например, следуя предложениям ответа здесь) (Альтернатива f, Интеграл a) => a -> a -> f a')? –

ответ

6

fail на самом деле не является монадической операцией; это только в классе Monad из-за исторической аварии/для скрытия грязной обработки ошибок.

Более подходящий класс для этого является MonadPlus, или, скорее, его Applicative корреспондентом Alternative. fail переводит на empty. При том, что ваша подпись на самом деле должна быть

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

, к которому Hoogle offers

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

Какой приспосабливает счет: Maybe является Foldable.

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

Возможно, на самом деле это не удобочитаемо.


Вы действительно можете достичь своей цели гораздо проще, написав

 Just c <- pure $ findC a b 

Это снова использовать fail метод: ошибки сопоставления с образцом в do блока называет его неявно.

Смежные вопросы