[Haskell-cafe] handling NULL value in database query with Maybe (or other ...)
Brandon Allbery
allbery.b at gmail.com
Wed Dec 19 16:17:52 UTC 2018
Haskell doesn't do "automatically"; the whole point is to force you to
handle these kinds of cases, not "just make it somehow work" in ways you
can't be certain are correct for your use case.
On Wed, Dec 19, 2018 at 11:15 AM Damien Mattei <mattei at oca.eu> wrote:
> 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
> _______________________________________________
> Haskell-Cafe mailing list
> To (un)subscribe, modify options or view archives go to:
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> Only members subscribed via the mailman list are allowed to post.
--
brandon s allbery kf8nh
allbery.b at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20181219/6c128d02/attachment.html>
More information about the Haskell-Cafe
mailing list