2014-09-10 2 views
6

Я хочу получить как минимум два значения, или если кто-то ничего не получает без ничего, или ничего не возвращает, если оба входа ничего. Я могу написать простую функцию для этого, но я подозреваю, что есть способ сделать это без написания пользовательской функции. Извините, если это мелкий вопрос, но есть ли более простой способ, чем использование этой настраиваемой функции?Minimum of Two Maybes

minMaybe :: Ord a => Maybe a -> Maybe a -> Maybe a 
minMaybe Nothing b = b 
minMaybe a Nothing = a 
minMaybe (Just a) (Just b) = Just $ min a b 
+0

до того, как я опустился вниз от этого поросенка;) ... как насчет: 'пусть minM a b = возможно, просто $ может быть b Просто $ min a b '? – Carsten

+0

Может быть, [только это] (http://ideone.com/GH4K7K) –

+0

n.m, это работает, но это не проще, чем то, с чего я начинаю. – clay

ответ

3

Вы не можете использовать Applicative или Monad экземпляр для этого, так как любой Nothing в этих условиях будет иметь ваш общий результат будучи Nothing. При этом термин «более простой» сильно самоуверен, и ваша функция прекрасна, как есть.

+2

Примечание: Сообщество wiki, так как «более простой» очень самоуверенный. – Zeta

+0

Поскольку 'max' работает как @clay, он хотел бы (« предпочитая »значения Just для Nothings), возможно, если @clay использовал Data.Ord.Down, тогда у них было бы поведение, которое они хотят, но все еще« проще »в как другие ответы хотят этого. – radomaj

3

Вы можете написать его с помощью Alternative экземпляр Maybe:

minMaybe a b = liftA2 min a b <|> a <|> b 

В качестве альтернативы, вы можете использовать maxBound по умолчанию, так что он всегда будет выбрать другой:

minMaybe a b = liftA2 min (d a) (d b) 
    where d x = x <|> Just maxBound 

Но я не Не рекомендую.

17

Возможно выполнение спецификации с использованием операторов от Control.Applicative.

myMin :: Ord x => Maybe x -> Maybe x -> Maybe x 
myMin a b = min <$> a <*> b <|> a <|> b 

<|> где для Maybe реализует "предпочтение"

Nothing <|> b = b 
a  <|> _ = a 

Дело в том,

min <$> Just a <*> Just b = Just (min a b) 

но

min <$> Just a <*> Nothing = Nothing 

, которая привела к некоторому incorre ct отвечает на этот вопрос. Используя <|>, вы можете предпочесть вычисленное значение min, когда оно доступно, но восстановить с любым человеком, если только один - Just.

Но вы должны спросить, целесообразно ли использовать Maybe таким образом. С бесславным исключением своего экземпляра Monoid, Maybe настроен для моделирования отказоустойчивых вычислений. Здесь у вас есть расширение существующего Ord с «верхним» элементом.

data Topped x = Val x | Top deriving (Show, Eq, Ord) 

и вы увидите, что min для Topped x это именно то, что вам нужно. Приятно думать о типах, а не о представлении данных, а о оборудовании данных со структурой. Nothing обычно представляет собой какой-то сбой, поэтому было бы лучше использовать другой тип для вашей цели.

+0

true, но вам понадобится другая структура данных для 'max' ... –

+3

' Topped x' имеет разумный 'max', но если вы хотите добавить элемент * bottom * вместо этого, то предполагаемая семантика изменится, поэтому почему тип должен оставаться прежним? Конечно, мы могли бы сделать конструкцию «сделать моноид из полугруппы» один раз, затем обернуть «max», «min» и т. Д. В виде полугрупповых структур. – pigworker

+1

'min <$> a <*> b == min a b' on' Maybe '. Последний, однако, выглядит более «в гольф», чем «более простой» ... – chi