2010-06-20 2 views
9

Как извлечь значение из переменной неизвестного конструктора?Соответствие шаблону в выражении let

Например, я хотел бы, чтобы свести на нет значение в Либо, если был построен как право:

let Right x = getValue 
in Right (negate x)

Этот код успешно связывает значение Райта (Int в этом случае) х.

Это работает, но что делать, если getValue возвращает слева? Есть ли способ определить тип переменной в выражении let? Или есть лучший способ подойти к этой проблеме?

ответ

17

В общем, то, что вы можете сделать это:

case getValue of 
    Right x -> Right $ negate x 
    e  -> e 

Что это делает должно быть ясны: это так же, как шаблон в качестве аргумента функции, но и против значения. Чтобы сделать то, что вам нужно, у вас есть случай по умолчанию, который ловит все, что не соответствует, а затем возвращает это.

В вашем конкретном случае, однако, вы можете сделать что-то немного приятнее:

negate `fmap` getValue 

Или, с import Control.Applicative, вы можете использовать <$> как синоним fmap (negate <$> getValue). Функция fmap имеет тип fmap :: Functor f => (a -> b) -> f a -> f b. Для любого функтора , fmap преобразует функцию по обычным значениям в функцию внутри функтора. Например, списки являются функторами, а для списков - fmap = map. Здесь Either e представляет собой функтор, который является либо исключением Left e, либо значением Right a; применение функции к Left ничего не делает, но применение функции к Right применяет ее в пределах Right. Другими словами,

instance Functor (Either e) where 
    fmap _ (Left l) = Left l 
    fmap f (Right r) = Right $ f r 

Таким образом, версия case является прямым ответом на ваш вопрос, но ваш конкретный пример более хорошо аппроксимируется fmap.

1: В первом приближении функторы являются «контейнерами». Если вам не нравятся различные типы классов, я рекомендовал the Typeclassopedia для получения полной справки; есть еще много учебников, и лучший способ почувствовать их - просто поиграть с ними. Тем не менее, fmap для конкретных типов часто можно использовать (особенно, на мой взгляд, при написании <$>).

+4

И не забываете хороший 'либо левый (правый отрицать.) GetValue' от' Data.Either';) – ony

+0

Благодарю. Выражение случая - это то, что я искал. Я не понимаю остальной части вашего ответа; Я вернусь к нему, когда узнаю больше. – titaniumdecoy

+0

@ony: Я думаю, что вы должны написать свой комментарий в виде отдельного ответа, это действительно решение промежуточного уровня между 'case' и' fmap'! – yatima2975

2

Ответ на названии этого вопроса:
я не вижу большой разницы между «... where» и «let ... in ...». И позволяет делать объявить несколько случаев аргументов функции привязок:

f val = let negR (Right x) = Right (negate x) 
      negR y = y 
     in negR val 

или let { negR (Right x) = Right (negate x); negR y = y; } in negR val

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