I am wondering if it is possible to wirte the Function
add :: Maybe Int -> Maybe Int
add Just x = Just (x 1)
add Nothing = Nothing
without the x
. Similar to
f = Just.( 1)
However
add Just = Just.( 1)
throws an error: Equations for 'add' have different numbers of arguments
.
Can someone please explain me why this does not work?
CodePudding user response:
You need to pattern match somewhere - there's no way to "get the value out" without doing so. You can use some unsafe function, like fromJust
, but
- it's unsafe - doing a case and pattern matching is better
- it's still doing pattern matching in it, so you're not really avoiding doing it.
The "proper modular" way to do this, would be to write this common pattern as a higher-order function, so that you can reuse it:
- in the
Nothing
case, you returnNothing
- in the
Just
case, you returnJust
of some function applied to the arg inside
Taking into account the two things above, we reach the following
maybeMap :: (a -> b) -> Maybe a -> Maybe b
maybeMap _ Nothing = Nothing
maybeMap f (Just x) = Just (f x)
which you can now use to write your desired function:
add :: Maybe Int -> Maybe Int
add x = maybeMap ( 1) x
-- or we can eta reduce it - taking an argument and calling a function with it is the same as just returning the function directly
add = maybeMap ( 1)
This function is traditionally called map, because you're mapping "the values inside a container" to something else.
This is something that you very often need to do for different "containers" (and some other kinds of things), so we have a type class for it in the standard library (base
), named after some theoretical things:
class Functor f where
fmap :: (a -> b) -> f a -> f b
instance Functor [] where
fmap = map
instance Functor Maybe where
fmap = maybeMap
Additionally, the error you're seeing is something else entirely. In Haskell, when writing a function definition, your different cases are not allowed to have different numbers of arguments taken:
-- not allowed, since in the first case you've taken two args,
-- but in the second you've only taken one.
bla :: Integer -> Integer -> Integer
bla 0 y = 42
bla x = id
-- this is fine, in both cases we have two arguments
bla :: Integer -> Integer -> Integer
bla 0 y = 42
bla x y = y
CodePudding user response:
The first parameter is a Maybe Int
, hence it is not sufficient to only specify the Just
data constructor: this data constructor has one parameter x
. You thus should use (Just x)
, (Just _)
or Just {}
to match where the last two ignore the value wrapped in the Just
data constructor. But in that case you thus can not access that value.
Your function however is a special case of an fmap :: Functor f => (a -> b) -> f a -> f b
with f ~ Maybe
and as mapping function ( 1)
. Indeed, the Functor
instance of Maybe
is implemented as [src]:
instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a)
You thus can implement add
as:
add :: Maybe Int -> Maybe Int
add = fmap (1 )