[Haskell-cafe] handling NULL value in database query with Maybe (or other ...)
Damien Mattei
mattei at oca.eu
Wed Dec 19 16:14:47 UTC 2018
thank tou for your C/HASKELL "rosetta stone" about the Monad it helps a
lot understanding the thing...
i always thougt Monads are powerful but they are not easy sot
manipulates syntactically for a beginner in Haskell.
yes in fact what i secretly expected was a way to discard NULL fields
automagically and it seems really possible with Haskell.
Le 19/12/2018 11:27, Mario Lang a écrit :
> Damien Mattei <mattei at oca.eu> writes:
>
>> using Nothing and Just compared to other language, it's the same than
>> if i had written in C something like :
>> if (x == NULL) printf("NULL\n");
>> else printf("%s",*x);
>>
>> i expected more from Haskell...
>
> Haskell actually offers more.
>
> 1. The type of "Maybe a" prevents you from ignoring the fact that "a" might
> be null. In C, you can accidentally write
>
> printf("%s",*x);
>
> and risking a segfault. The compiler will not care. IN Haskell, the
> types dont even allow you to write something like that. You would be
> forced to check for Just or Nothing in one of several ways.
>
> Now, "Maybe a" doesn't only limit your abilities, it also offers you the
> functions from the Functor, Applicative and Monad typeclasses.
>
> 2. Functor allows you to apply a function to the "a", as long as there is
> some "a" inside the "Maybe a". So, "fmap f x" is roughly equivalent to:
>
> typeOfA f(typeOfA);
> typeOfA *x func(typeOfA *x) {
> if (x) {
> typeOfA *val = malloc(sizeof(typeOfA));
> *val = f(*x);
> return val;
> }
> return NULL;
> }
> func(x);
>
> (note that pure Haskell doesn't have assignment, so the translation to C
> is a little bit more verbose then it might be if you were using values
> on the stack.)
i tried this:
let resFMAP = fmap (\(Only a) -> (putStrLn ("a =" ++ Text.unpack a)))
bd_rows_WDS
but compile complains now that i use a Maybe variable instead of a plain
one,strange because this exactly what i expected from Maybe use it to
automatically discard the Nothing values (avoiding to putStrln them):
Prelude> :load UpdateSidonie
[1 of 1] Compiling Main ( UpdateSidonie.hs, interpreted )
UpdateSidonie.hs:293:75: error:
• Couldn't match type ‘Maybe Text’ with ‘Text’
Expected type: [Only Text]
Actual type: [Only (Maybe Text)]
• In the second argument of ‘fmap’, namely ‘bd_rows_WDS’
In the expression:
fmap (\ (Only a) -> (putStrLn ("a =" ++ unpack a))) bd_rows_WDS
In an equation for ‘resFMAP’:
resFMAP
= fmap (\ (Only a) -> (putStrLn ("a =" ++ unpack a)))
bd_rows_WDS
|
293 | let resFMAP = fmap (\(Only a) -> (putStrLn ("a =" ++
Text.unpack a))) bd_rows_WDS
|
^^^^^^^^^^^
Failed, no modules loaded.
bd_rows_WDS is defined like this with a Maybe:
(bd_rows_WDS :: [Only (Maybe Text)]) <- query conn qry_head_WDS (Only
(name::String))
anyway i know enought in haskell now to remove myself the Nothing (NULL)
values of the list doing that (it worked):
-- remove the records having N°BD NULL
let fltWDS = Prelude.filter (\(Only a) ->
case a of
Nothing -> False
Just a -> True)
bd_rows_WDS
>
> So you do not need to write an explicit if in Haskell. The Functor
> instance of Maybe "knows" how to deal will null cases.
> In particular, if it encounters a Nothing, it returns a Nothing,
> ignoring the provided function.
>
> 3. Applicative allows you to apply a function to the "a"s of several "Maybe a"
> values, returning a Maybe wrapping the result of that function.
> So "f <$> x <*> y" is equivalent to
>
> typeOfA f(TypeOfA);
> typeOfA *func(typeOfA *x, typeOfA *y) {
> if (x && y) {
> typeOfA *val = malloc(sizeof(typeOfA));
> *val = f(*x, *y);
> return val;
> }
> return NULL;
> }
> func(x, y);
>
> The amount of boilerplate eliminated grows.
>
> 3. Monad allows you to chain several null-checks without having to write
> out the nesting. This time, f, g and h return a "Maybe a", not just an "a":
>
> do
> a <- f x
> b <- g a
> h b
>
> or
>
> f x >>= \a -> g a >>= \b -> h b
>
> is equvalent to something like
>
> typeOfA *f(typeOfA);
> typeOfA *g(typeOfA);
> typeOfA *h(typeOfA);
> typeOfA *func(typeOfA x) {
> if (x) {
> type *a = f(*x);
> if (a) {
> type *b = g(*a);
> if (b) {
> return f(*b);
> }
> }
> }
> return NULL;
> }
>
> or, in Haskell:
>
> case f x of
> Just a -> case g a of
> Just b -> h b
> Nothing -> Nothing
> Nothing -> Nothing
>
> The Monad typeclass really pays off, as it saves you from doing the null
> checks and dereferencing. The nested "if null then null" stuff goes all
> away, and you can chain several functions together that return a
> possible null value.
>
>> ok reading twice the article in link, i admit there should be some
>> adavantage using Nothing instead of null, such as type, and genericity
>> and not being spcecific to alloated memory as in C ...
>
> Exactly. As I see it, the Functor, Applicative and Monad typeclasses
> of the Maybe type give you the tools
> necessary to reduce the boilerplate that results from forcing you to
> deal with each and every null case in your code.
>
--
Damien.Mattei at unice.fr, Damien.Mattei at oca.eu, UNS / OCA / CNRS
More information about the Haskell-Cafe
mailing list