Как Вы извлекаете значение из переменной неизвестного конструктора?
Например, я хотел бы инвертировать значение в Также, если бы был создан как Право:
let Right x = getValue
in Right (negate x)
Этот код успешно связывает значение Права (Интервал в этом случае) к x.
Это работает, но что, если getValue возвращает Левое вместо этого? Существует ли способ определить тип переменной в выражении, которому позволяют? Или есть ли лучший способ приблизиться к этой проблеме?
В общем, вы можете сделать следующее:
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
. Для любого функтора1, 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: В первом приближении, функторы - это "контейнеры". Если вы плохо ориентируетесь в различных классах типов, я рекомендую Typeclassopedia в качестве исчерпывающего справочника; есть еще много учебников, и лучший способ получить представление о них - просто поиграть с ними. Однако, fmap
для конкретных типов часто легко использовать (особенно, на мой взгляд, когда написано <$>
).
Ответьте на заголовок этого вопроса:
Я не вижу большой разницы между « ... где
» и « впускаем ...
». Оба позволяют объявить несколько случаев привязки аргументов функции:
f val = let negR (Right x) = Right (negate x)
negR y = y
in negR val
или
let {negR (Right x) = Right (отрицать x); negR y = y; } in negR val