[Haskell-cafe] Handling NULL value , was :trace output statements
Damien Mattei
damien.mattei at gmail.com
Thu Dec 27 00:03:10 UTC 2018
finally, late in night i got myself a working solution :-) :
getBD2 :: Connection -> String -> IO (Maybe Float)
getBD2 conn name = do
let qry_head_BD_Sidonie = "select `N° BD` from Coordonnées
where Nom = ?" :: Query
(bd_rows :: [Only (Maybe Text)]) <- query conn
qry_head_BD_Sidonie (Only (name::String))
let noBDtxt = fromOnly (Prelude.head bd_rows) :: Maybe Text
case noBDtxt of
Nothing -> return Nothing
Just noBDtxt -> do
putStrLn "getBD2"
let noBDstr = Text.unpack noBDtxt ::
String
let noBDfp = readMaybe noBDstr :: Maybe
Float
return noBDfp
note that i had to change read in readMaybe due to Exception: Prelude.read:
no parse,solved here (i do not really understand why) :
https://stackoverflow.com/questions/27947925/haskell-prelude-read-no-parse-string
note also in the last lines i infer a Maybe Float from a NOT maybe String ,
but the compiler did not notice it....
in my main function i call and display like that:(2 solution due to a Just
appearing in terminal...)
noBD <- getBD2 conn name
putStrLn ("noBD = " ++ (show noBD))
putStrLn $ "noBD = " ++ maybe "NULL" show noBD
display like this:
getBD2
noBD = Just (-4.3982)
noBD = -4.3982
but if someone has a more elegant or concise solution ? ....
my opinion: Haskell is weird... :-)
On Wed, Dec 26, 2018 at 11:24 PM Damien Mattei <damien.mattei at gmail.com>
wrote:
> i'm learning fmap, but for now i want to convert the previous function:
>
> getBD :: Connection -> String -> IO Float
> getBD conn name = do
> let qry_head_BD_Sidonie = "select `N° BD` from Coordonnées
> where Nom = ?" :: Query
> (bd_rows :: [Only Text]) <- query conn qry_head_BD_Sidonie
> (Only (name::String))
> let noBDtxt = fromOnly (Prelude.head bd_rows) :: Text
> let noBDstr = Text.unpack noBDtxt :: String
> let noBDfp = read $ noBDstr :: Float
> return noBDfp
>
> that works but fails in case of NULL in database,
> i want the code to works also with NULL, detecting them with Nothing, and
> short circuit them with Maybe or something else, so i change the function
> definition to this type and here is the whole code:
>
> getBD2 :: Connection -> String -> IO (Maybe Float)
> getBD2 conn name = do
> let qry_head_BD_Sidonie = "select `N° BD` from Coordonnées
> where Nom = ?" :: Query
> (bd_rows :: [Only (Maybe Text)]) <- query conn
> qry_head_BD_Sidonie (Only (name::String))
> let noBDtxt = if (isNothing (fromOnly (Prelude.head bd_rows)))
> then (return Nothing)
> else (fromOnly (Prelude.head bd_rows) :: Maybe
> Text)
> let noBDstr = Text.unpack noBDtxt :: Maybe String
> let noBDfp = read $ noBDstr :: Maybe Float
> return noBDfp
>
> unfortunately it fails to compile, something is wrong here:
>
> Prelude Data.Maybe> :load UpdateSidonie
> [1 of 1] Compiling Main ( UpdateSidonie.hs, interpreted )
>
> UpdateSidonie.hs:68:33: error:
> • Couldn't match type ‘Text’ with ‘Maybe a’
> Expected type: Maybe (Maybe a)
> Actual type: Maybe Text
> • In the expression:
> (fromOnly (Prelude.head bd_rows) :: Maybe Text)
> In the expression:
> if (isNothing (fromOnly (Prelude.head bd_rows))) then
> (return Nothing)
> else
> (fromOnly (Prelude.head bd_rows) :: Maybe Text)
> In an equation for ‘noBDtxt’:
> noBDtxt
> = if (isNothing (fromOnly (Prelude.head bd_rows))) then
> (return Nothing)
> else
> (fromOnly (Prelude.head bd_rows) :: Maybe Text)
> • Relevant bindings include
> noBDtxt :: Maybe (Maybe a) (bound at UpdateSidonie.hs:66:17)
> |
> 68 | else (fromOnly (Prelude.head bd_rows) ::
> Maybe Text)
> |
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> UpdateSidonie.hs:69:27: error:
> • Couldn't match type ‘[Char]’ with ‘Maybe String’
> Expected type: Maybe String
> Actual type: String
> • In the expression: unpack noBDtxt :: Maybe String
> In an equation for ‘noBDstr’:
> noBDstr = unpack noBDtxt :: Maybe String
> In the expression:
> do let qry_head_BD_Sidonie = ...
> (bd_rows :: [Only (Maybe Text)]) <- query
> conn qry_head_BD_Sidonie
> (Only (name :: String))
> let noBDtxt = ...
> let noBDstr = ...
> ....
> |
> 69 | let noBDstr = Text.unpack noBDtxt :: Maybe String
> | ^^^^^^^^^^^^^^^^^^^
>
> UpdateSidonie.hs:69:39: error:
> • Couldn't match expected type ‘Text’
> with actual type ‘Maybe (Maybe a0)’
> • In the first argument of ‘unpack’, namely ‘noBDtxt’
> In the expression: unpack noBDtxt :: Maybe String
> In an equation for ‘noBDstr’:
> noBDstr = unpack noBDtxt :: Maybe String
> |
> 69 | let noBDstr = Text.unpack noBDtxt :: Maybe String
> | ^^^^^^^
>
> UpdateSidonie.hs:70:33: error:
> • Couldn't match type ‘Maybe String’ with ‘[Char]’
> Expected type: String
> Actual type: Maybe String
> • In the second argument of ‘($)’, namely ‘noBDstr’
> In the expression: read $ noBDstr :: Maybe Float
> In an equation for ‘noBDfp’: noBDfp = read $ noBDstr :: Maybe Float
> |
> 70 | let noBDfp = read $ noBDstr :: Maybe Float
> | ^^^^^^^
> Failed, no modules loaded.
>
> what is the solution? it will help me in my project and to understand
> Haskell way of handling null objects.
>
> Damien
>
>
> On Tue, Dec 25, 2018 at 11:18 PM Ian Denhardt <ian at zenhack.net> wrote:
>
>>
>> (Adding the list back to Cc; you forgot to hit reply all)
>>
>> Quoting Damien Mattei (2018-12-25 16:57:04)
>>
>> > i get in trouble understanding what fmap was doing,
>>
>> fmap (for IO) just applies a function to the result of the action, so:
>>
>> fmap f action
>>
>> is equivalent to:
>>
>> do
>> result <- action
>> return (f result)
>>
>> > and why the same thing to do in main and in a function had so
>> > different implementations...
>>
>> I suspect the modified version of the program has some differences that
>> aren't strictly necessary just to factor out the relevant bits into
>> their own definition; this *shouldn't* be major surgery. Hard for me to
>> point out without having the two full examples handy.
>>
>> Quoting Damien Mattei (2018-12-25 16:57:04)
>> > yes, i understand with your python example, it's like read on a web
>> > page, IO are not a "cake" but IO are "a recipe for the cake"...
>> > functions are pure in haskell, so they can not have side effects...
>> > what put me some trouble is an answer 2 weeks ago, someone gave me
>> > hints that lead to this solution for getDB:
>> > getBD :: Connection -> String -> IO Float
>> > getBD conn name = trace "Entering getBD" noBDfp
>> > � where qry_head_BD_Sidonie = "select `N° BD` from Coordonnées where
>> > Nom = ?" :: Query
>> > � � � � � � � bd_rows :: IO [Only Text]
>> > � � � � � � � bd_rows = query conn qry_head_BD_Sidonie (Only
>> > (name::String))
>> > � � � � � � � noBDtxt :: IO Text
>> > � � � � � � � noBDtxt = trace "assigning noBDtxt" (fmap (fromOnly .
>> > Prelude.head) bd_rows)
>> > � � � � � � � noBDstr :: IO String
>> > � � � � � � � noBDstr = trace "assigning noBDstr" (fmap Text.unpack
>> > noBDtxt)
>> > � � � � � � � noBDfp :: IO Float
>> > � � � � � � � noBDfp = fmap read noBDstr
>> > which was code different from the code in main,i get in trouble
>> > understanding what fmap was doing , and why the same thing to do in
>> > main and in a function had so different implementations...
>> >
>> > On Tue, Dec 25, 2018 at 10:19 PM Ian Denhardt <[1]ian at zenhack.net>
>> > wrote:
>> >
>> > The correct type annotation for getDB3 should be:
>> > � � getDB3 :: Connection -> String -> IO Float
>> > Note the IO at the end. Functions in Haskell are just pure
>> > computation;
>> > they can't have side effects -- so a function returning a Float
>> > can't
>> > possibly talk to a database.
>> > Instead, The type `IO a` represents a description of an action to
>> > perform.� It's still just a value -- calling getDB3 doesn't *do*
>> > anything. You can stitch these together using do-notation or
>> > functions
>> > like >>=, and when the program is run the action defined by 'main'
>> > is
>> > performed.
>> > ---
>> > An analogy: you could imagine instead of IO we could give up, and
>> > write
>> > code that computes a program in some other (imperative) programming
>> > language) that we then hand off to an interpreter. For example, we
>> > could
>> > compute a python program that counts from 1 to 99 like so:
>> > � � printNum :: Int -> String
>> > � � printNum n = "print('" ++ show n ++ "')\n"
>> > � � pythonProgram = concatMap printNum [1..99]
>> > So we've defined a variable fullProgram that is a string with the
>> > source
>> > code to a python program like:
>> > � � print('1')
>> > � � print('2')
>> > � � print('3')
>> > � � ...
>> > � � print('99')
>> > ..but we haven't actually run it. To do that we'd have to pass the
>> > string off to the python interpreter.
>> > This is a good way to think about what IO is -- main is like our
>> > pythonProgram above, in that it is a description of actions to
>> > perform,
>> > but *evaluating* it doesn't have any side effects -- it just
>> > computes
>> > the description. When you run a Haskell program, this is like
>> taking
>> > the description defined by Main and passing it off to an
>> > interpreter.
>> > ---
>> > So your definition of getDB3 is a description of actions to perform
>> > to
>> > get a float from the database, but your type declaration says it's
>> a
>> > function that computes a float (without having to perform any
>> > "actions").
>> > This is a critical distinction that exists in Haskell but not most
>> > other
>> > languages.
>> > Hope this helps,
>> > -Ian
>> > Quoting Damien Mattei (2018-12-25 15:07:35)
>> > >� � yes i use do notation, but for example i have code that
>> works
>> > in main
>> > >� � and not in a function!
>> > >� � i print the code perheaps someone could help me:
>> > >� � first the function, so you have the import list too:
>> > >� � import Database.MySQL.Simple
>> > >� � import Database.MySQL.Simple.QueryResults
>> > >� � import Database.MySQL.Simple.Result
>> > >� � import Database.MySQL.Simple.QueryParams
>> > >� � import Database.MySQL.Simple.Param
>> > >� � import Control.Monad
>> > >� � import Data.Text as Text
>> > >� � --import Data.Int as Int
>> > >� � --import Data.List
>> > >� � import Debug.Trace
>> > >� � import Data.Maybe as Maybe
>> > >� � -- this function will return th N°BD from Sidonie for a
>> > given name
>> > >� � -- note: names have been standardized between Sidonie and
>> WDS
>> > >� � getBD3 :: Connection -> String -> Float
>> > >� � getBD3 conn name = do
>> > >� � � � � � � � � � � � �� let
>> > qry_head_BD_Sidonie = "select `N° BD` from
>> > >� � Coordonnées where Nom = ?" :: Query
>> > >� � � � � � � � � � � � �� (bd_rows ::
>> > [Only Text]) <- query conn
>> > >� � qry_head_BD_Sidonie (Only (name::String))
>> > >� � � � � � � � � � � � �� let noBDtxt =
>> > fromOnly (Prelude.head bd_rows) ::
>> > >� � Text
>> > >� � � � � � � � � � � � �� let noBDstr =
>> > Text.unpack noBDtxt :: String
>> > >� � � � � � � � � � � � �� let noBDfp =
>> > read $ noBDstr :: Float
>> > >� � � � � � � � � � � � �� return noBDfp
>> > >� � with this function i have this error:
>> > >� � Prelude> :load UpdateSidonie
>> > >� � [1 of 1] Compiling Main� � � � � � � � �
>> > � � �� ( UpdateSidonie.hs,
>> > >� � interpreted )
>> > >� � UpdateSidonie.hs:54:13: error:
>> > >� � � � �� � Couldn't match expected type �Float�
>> > with actual type �IO
>> > >� � Float�
>> > >� � � � �� � In a stmt of a 'do' block:
>> > >� � � � � � � � �� (bd_rows :: [Only Text]) <-
>> > query
>> > >� � � � � � � � � � � � � � � � �
>> > � � � � � � � � � � � � � � � � �
>> > � � � �
>> > >� � � �� conn qry_head_BD_Sidonie (Only (name :: String))
>> > >� � � � � � �� In the expression:
>> > >� � � � � � � � �� do let qry_head_BD_Sidonie =
>> > ...
>> > >� � � � � � � � � � � �� (bd_rows :: [Only
>> > Text]) <- query
>> > >� � � � � � � � � � � � � � � � �
>> > � � � � � � � � � � � � � � � � �
>> > � � � �
>> > >� � � � � � �� conn qry_head_BD_Sidonie (Only (name ::
>> > String))
>> > >� � � � � � � � � � � �� let noBDtxt = ...
>> > >� � � � � � � � � � � �� let noBDstr = ...
>> > >� � � � � � � � � � � �� ....
>> > >� � � � � � �� In an equation for �getBD3�:
>> > >� � � � � � � � � � �� getBD3 conn name
>> > >� � � � � � � � � � � � �� = do let
>> > qry_head_BD_Sidonie = ...
>> > >� � � � � � � � � � � � � � � � �
>> > �� (bd_rows :: [Only Text]) <- query
>> > >� � � � � � � � � � � � � � � � �
>> > � � � � � � � � � � � � � � � � �
>> > � � � �
>> > >� � � � � � � � � � � � �� conn
>> > qry_head_BD_Sidonie (Only (name :: String))
>> > >� � � � � � � � � � � � � � � � �
>> > �� let noBDtxt = ...
>> > >� � � � � � � � � � � � � � � � �
>> > �� ....
>> > >� � � �� |
>> > >� � 54 |� � � � � � � � � � � ��
>> > (bd_rows :: [Only Text]) <- query conn
>> > >� � qry_head_BD_Sidonie (Only (name::String))
>> > >� � � �� |� � � � � � � � � � � �
>> > >� �
>> >
>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> > ^^^
>> > >� � ^^^^^^^^^
>> > >� � Failed, no modules loaded.
>> > >� � i do not understand the error complaining that i return an
>> IO
>> > >� � float,because i'm sure it's a float in noBDfp
>> > >� � if i put the same lines of code in the main it works !!! :
>> > >� � main :: IO ()
>> > >� � main =
>> > >� � �� do
>> > >� � � � �� conn <- connect defaultConnectInfo
>> > >� � � � � � �� { connectHost = "moita",
>> > >� � � � � � � � �� connectUser = "mattei",
>> > >� � � � � � � � �� connectPassword = "sidonie2",
>> > >� � � � � � � � �� connectDatabase = "sidonie" }
>> > >� � � let qry_head_BD_Sidonie = "select `N° BD` from
>> > Coordonnées where
>> > >� � Nom = ?" :: Query
>> > >� � � (bd_rows :: [Only Text]) <- query conn
>> > qry_head_BD_Sidonie (Only
>> > >� � (name::String))
>> > >� � putStr "bd_rows ="
>> > >� � putStrLn $ show bd_rows
>> > >� � � � �� let noBDtxt = fromOnly (Prelude.head bd_rows)
>> > :: Text
>> > >� � � � �� let noBDstr = Text.unpack noBDtxt :: String
>> > >� � � � �� let noBDfp = read $ noBDstr :: Float
>> > >� � � � �� putStr "noBDfp ="
>> > >� � � � �� (putStrLn (show noBDfp))
>> > >� � � close conn
>> > >� � it works i have output like this:
>> > >� � *Main> main
>> > >� � bd_rows =[Only {fromOnly = "-04.3982"}]
>> > >� � noBDtxt ="-04.3982"
>> > >� � noBDfp =-4.3982
>> > >� � noBDfp + 1 = -3.3982
>> > >� � i'm well getting a float in noBDfp , i even can add 1 to it
>> > :-) ( cool
>> > >� � haskell...)
>> > >� � but i'm just wanting to that in the function getDB3 but it
>> > does not
>> > >� � compile...
>> > >� � ??????
>> > >� � Damien
>> > >
>> > >� � On Sun, Dec 23, 2018 at 4:54 PM Tom Ellis
>> > >� � <[1][2]tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk> wrote:
>> > >
>> > >� � � I think forgetting about monads and just using
>> do-notation
>> > will help
>> > >� � � you.
>> > >� � � On Sun, Dec 23, 2018 at 04:44:57PM +0100, Damien Mattei
>> > wrote:
>> > >� � � > i think learning Monads from scratch again will help me
>> > >� � � >
>> > >� � � > On Sun, Dec 23, 2018 at 4:11 PM Tom Ellis <
>> > >� � � > [2][3]tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk>
>> > wrote:
>> > >� � � >
>> > >� � � > > Yes, exactly!
>> > >� � � > >
>> > >� � � > > On Sun, Dec 23, 2018 at 02:08:57PM +0100, Damien
>> > Mattei wrote:
>> > >� � � > > > lazyness....?
>> > >� � � > > >
>> > >� � � > > > On Sun, Dec 23, 2018 at 8:40 AM Tom Ellis <
>> > >� � � > > > [3][4]tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk>
>> > wrote:
>> > >� � � > > >
>> > >� � � > > > > On Sat, Dec 22, 2018 at 09:52:18AM +0100, Damien
>> > Mattei
>> > >� � � wrote:
>> > >� � � > > > > > i have inserted trace statement that output
>> > variable
>> > >� � � > > > > > ... i have strange behavior of output:
>> > >� � � > > > >
>> > >� � � > > > > Let's take a simpler example.�� Do you
>> > understand why the
>> > >� � � trace
>> > >� � � > > statments
>> > >� � � > > > > from this small program appear in the order that
>> > they do?�
>> > >� � � (And for
>> > >� � � > > what
>> > >� � � > > > > it's worth I really think you'll be better off
>> > writing
>> > >� � � programs using
>> > >� � � > > do
>> > >� � � > > > > notation).
>> > >� � � > > > >
>> > >� � � > > > >
>> > >� � � > > > > % cat test.hs
>> > >� � � > > > > import Debug.Trace
>> > >� � � > > > >
>> > >� � � > > > > result =
>> > >� � � > > > >�� � let a = trace "evaluating a" 2
>> > >� � � > > > >�� �� �� � b = trace "evaluating b" 10
>> > >� � � > > > >�� �� �� � c = trace "evaluating c" (a +
>> > b)
>> > >� � � > > > >�� � in c
>> > >� � � > > > > ~% ghci -e result test.hs
>> > >� � � > > > > evaluating c
>> > >� � � > > > > evaluating b
>> > >� � � > > > > evaluating a
>> > >� � � > > > > 12
>> > >� � � > > _______________________________________________
>> > >� � � > > Haskell-Cafe mailing list
>> > >� � � > > To (un)subscribe, modify options or view archives go
>> > to:
>> > >� � � > >
>> > [4][5]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > >� � � > > Only members subscribed via the mailman list are
>> > allowed to
>> > >� � � post.
>> > >� � � > _______________________________________________
>> > >� � � > Haskell-Cafe mailing list
>> > >� � � > To (un)subscribe, modify options or view archives go
>> to:
>> > >� � � >
>> > [5][6]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > >� � � > Only members subscribed via the mailman list are
>> allowed
>> > to post.
>> > >� � � _______________________________________________
>> > >� � � Haskell-Cafe mailing list
>> > >� � � To (un)subscribe, modify options or view archives go to:
>> > >� � �
>> > [6][7]
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > >� � � Only members subscribed via the mailman list are allowed
>> > to post.
>> > >
>> > > Verweise
>> > >
>> > >� � 1. mailto:[8]tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > >� � 2. mailto:[9]tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > >� � 3. mailto:[10]tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > >� � 4.
>> > [11]http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > >� � 5.
>> > [12]http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > >� � 6.
>> > [13]http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> >
>> > Verweise
>> >
>> > 1. mailto:ian at zenhack.net
>> > 2. mailto:tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > 3. mailto:tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > 4. mailto:tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > 5. http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > 6. http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > 7. http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > 8. mailto:tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > 9. mailto:tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > 10. mailto:tom-lists-haskell-cafe-2017 at jaguarpaw.co.uk
>> > 11. http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > 12. http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>> > 13. http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20181227/1cce3ee4/attachment-0001.html>
More information about the Haskell-Cafe
mailing list