How do you extract a value from a variable of an unknown constructor?
For instance, I would like to negate the value in an Either if was constructed as a Right:
let Right x = getValue
in Right (negate x)
This code successfully binds Right's value (an Int in this case) to x.
This works, but what if getValue returns a Left instead? Is there a way to determine the type of a variable in a let expression? Or is there a better way to approach this problem?
You can use pattern matching to test the shape and values of the data instead of transforming it into a set of objects.
Pattern matching is the process of checking whether a specific sequence of characters/tokens/data exists among the given data. Regular programming languages make use of regular expressions (regex) for pattern matching.
The pattern-matching algorithm uses a variety of techniques to match different kinds of expression. Data elements such as numbers, strings, booleans are matched by comparison: a pattern consisting of a single data element matches only that exact element.
In general, what you can do is this:
case getValue of
Right x -> Right $ negate x
e -> e
What this does should be clear: it's just like pattern matching in a function argument, but against a value. To do what you need, you have a default case which catches anything not matched, and then return that.
In your particular case, however, you can do something slightly nicer:
negate `fmap` getValue
Or, with import Control.Applicative
, you can use <$>
as a synonym for fmap
(negate <$> getValue
). The fmap
function has type fmap :: Functor f => (a -> b) -> f a -> f b
. For any functor1, fmap
converts a function on ordinary values to a function within the functor. For instance, lists are a functor, and for lists, fmap = map
. Here, Either e
represents a functor which is either an exception Left e
or a value Right a
; applying a function to a Left
does nothing, but applying a function to a Right
applies it within the Right
. In other words,
instance Functor (Either e) where
fmap _ (Left l) = Left l
fmap f (Right r) = Right $ f r
Thus the case
version is the direct answer to your question, but your particular example is more nicely approximated by fmap
.
1: To a first approximation, functors are "containers". If you're not comfortable with the various type classes, I recommed the Typeclassopedia for a comprehensive reference; there are many more tutorials out there, and the best way to get a feel for them is to just play with them. However, the fmap
for specific types is often readily usable (especially, in my opinion, when written <$>
).
Answer to the title of this question:
I don't see big difference between "... where
" and "let ... in ...
". Both allows you do declare several cases of function argument bindings:
f val = let negR (Right x) = Right (negate x)
negR y = y
in negR val
or
let { negR (Right x) = Right (negate x); negR y = y; } in negR val
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With