Fwd: [Haskell-beginners] monad and variable result

i'v got no solution from Haskell-beginners...
perheaps is there some expert here?
-------- Message transféré --------
Sujet : [Haskell-beginners] monad and variable result
Date : Mon, 10 Dec 2018 11:32:23 +0100
De : Damien Mattei

Hi Damien, On Mon, Dec 10, 2018 at 03:18:48PM +0100, Damien Mattei wrote:
have some code that works but want to put it in a simple function without sucess:
getBD :: Connection -> String -> Float getBD conn name = noBDfp where qry_head = "select `N° BD` from sidonie.Coordonnées where Nom = ?" :: Query bd_rows = do local_bd_rows <- query conn qry_head (Only (name::String)) return local_bd_rows
i want the variable local_bd_rows accessible in the 'where' clause
how can i do that?
You don’t seem to be using the function bd_rows anywhere in the main body of the definition. You would need to do something like getBD :: Connection -> String -> IO Float getBD = do rows <- bd_rows {- code that does something with the returned data -} Note the change to the type signature—querying the database is an IO action, and therefore takes place in the IO monad. Incidently, your use of do notation in the definition of bd_rows is unnecessary: do x <- doSomething return x is actually syntactic sugar for doSomething >>= \x -> return x which the monad laws state is equivalent to just doSomething. This is a common misapprehension among Haskell novices: the do notation is just a syntactic convenience, and it is perfectly possible to write monadic functions, including in the IO monad, without it. Hope at least some of this helps. Seph -- Seph Shewell Brockway, BSc MSc (Glas.)

for now i'm here: getBD :: Connection -> String -> Float getBD conn name = noBDfp where qry_head = "select `N° BD` from sidonie.Coordonnées where Nom = ?" :: Query -- bd_rows = -- do -- local_bd_rows <- query conn qry_head (Only (name::String)) -- return local_bd_rows bd_rows :: IO [Only Text] bd_rows = query conn qry_head (Only (name::String)) noBDtxt :: [Text] noBDtxt = fromOnly (Prelude.head bd_rows) noBDstr :: String noBDstr = Text.unpack noBDtxt :: String noBDfp = read $ noBDstr :: Float but it fails due to the IO : Prelude> :load UpdateSidonie [1 of 1] Compiling Main ( UpdateSidonie.hs, interpreted ) UpdateSidonie.hs:53:42: error: • Couldn't match expected type ‘[Only [Text]]’ with actual type ‘IO [Only Text]’ • In the first argument of ‘Prelude.head’, namely ‘bd_rows’ In the first argument of ‘fromOnly’, namely ‘(Prelude.head bd_rows)’ In the expression: fromOnly (Prelude.head bd_rows) | 53 | noBDtxt = fromOnly (Prelude.head bd_rows) | ^^^^^^^ UpdateSidonie.hs:55:31: error: • Couldn't match expected type ‘Text’ with actual type ‘[Text]’ • In the first argument of ‘unpack’, namely ‘noBDtxt’ In the expression: unpack noBDtxt :: String In an equation for ‘noBDstr’: noBDstr = unpack noBDtxt :: String | 55 | noBDstr = Text.unpack noBDtxt :: String | ^^^^^^^ Failed, no modules loaded. Le 10/12/2018 17:19, Seph Shewell Brockway a écrit :
Hi Damien,
On Mon, Dec 10, 2018 at 03:18:48PM +0100, Damien Mattei wrote:
have some code that works but want to put it in a simple function without sucess:
getBD :: Connection -> String -> Float getBD conn name = noBDfp where qry_head = "select `N° BD` from sidonie.Coordonnées where Nom = ?" :: Query bd_rows = do local_bd_rows <- query conn qry_head (Only (name::String)) return local_bd_rows
i want the variable local_bd_rows accessible in the 'where' clause
how can i do that?
You don’t seem to be using the function bd_rows anywhere in the main body of the definition. You would need to do something like
getBD :: Connection -> String -> IO Float getBD = do rows <- bd_rows {- code that does something with the returned data -}
Note the change to the type signature—querying the database is an IO action, and therefore takes place in the IO monad.
Incidently, your use of do notation in the definition of bd_rows is unnecessary:
do x <- doSomething return x
is actually syntactic sugar for
doSomething >>= \x -> return x
which the monad laws state is equivalent to just doSomething. This is a common misapprehension among Haskell novices: the do notation is just a syntactic convenience, and it is perfectly possible to write monadic functions, including in the IO monad, without it.
Hope at least some of this helps.
Seph
-- Damien.Mattei@unice.fr, Damien.Mattei@oca.eu, UNS / OCA / CNRS

On Mon, Dec 10, 2018 at 06:06:30PM +0100, Damien Mattei wrote:
for now i'm here:
getBD :: Connection -> String -> Float getBD conn name = noBDfp where qry_head = "select `N° BD` from sidonie.Coordonnées where Nom = ?" :: Query -- bd_rows = -- do -- local_bd_rows <- query conn qry_head (Only (name::String)) -- return local_bd_rows bd_rows :: IO [Only Text] bd_rows = query conn qry_head (Only (name::String)) noBDtxt :: [Text] noBDtxt = fromOnly (Prelude.head bd_rows) noBDstr :: String noBDstr = Text.unpack noBDtxt :: String noBDfp = read $ noBDstr :: Float
Okay, I think I understand how your code is structured now. The point to recognize is that bd_rows has type IO [Only Text], which is not the same type as [Only Text]. Prelude.head has the type [a] -> a, and so it can’t be used on bd_rows as-is. Fortunately, being a monad, IO has an instance of Functor for free, and we can go from head :: [Only Text] -> Only Text to fmap head :: IO [Only Text] -> IO (Only Text) which takes an IO operation returning [Only Text] and applies head to its result, giving an IO operation returning an Only Text. Can you see how the IO monad follows you through everything that uses its result? If you rewrite noBDtxt as noBDtxt :: IO [Text] noBDtxt = fmap (fromOnly . Prelude.head) bd_rows then noBDstr has to be rewritten in a similar way, and so on through to the final result, giving the main function a type of Connection -> String -> IO Float. A lot of the functions in your where clause can be amalgamated, for example by combining noBDtxt and noBDstr as noBDstr = fmap (Text.unpack . fromOnly . Prelude.head) Similarly, getBD takes the result of noBDfp and returns it unaltered, so why not just write getBD = fmap read noBDstr ? Let me know if you would like me to explain anything in this message in more detail. Regards, Seph -- Seph Shewell Brockway, BSc MSc (Glas.)

Thank you Seph, with your help and reading some pages i can get to this: getBD :: Connection -> String -> IO Float getBD conn name = noBDfp where qry_head = "select `N° BD` from sidonie.Coordonnées where Nom = ?" :: Query bd_rows :: IO [Only Text] bd_rows = query conn qry_head (Only (name::String)) -- noBDtxt :: [Text] -- noBDtxt = fromOnly (Prelude.head bd_rows) -- noBDtxt :: IO [Text] noBDtxt :: IO Text noBDtxt = fmap (fromOnly . Prelude.head) bd_rows -- noBDstr :: String -- noBDstr = Text.unpack noBDtxt noBDstr :: IO String noBDstr = fmap Text.unpack noBDtxt -- noBDfp = read $ noBDstr :: Float noBDfp = fmap read noBDstr :: IO Float which compile but the question rest entire :how can i get the loat number from all this? i have a Main that looks like this: main :: IO () --main :: Int main = do conn <- connect defaultConnectInfo { connectHost = "moita", connectUser = "mattei", connectPassword = "sidonie2", connectDatabase = "sidonie" } -- first we get the N°BD from sidonie let name = "A 20" let noBD_IO = getBD conn name -- putStrLn $ show $ read $ Text.unpack noBD_IO close conn print "Exit." how can i get the float number from noBD_IO ? Regards, Damien Le 10/12/2018 19:56, Seph Shewell Brockway a écrit :
On Mon, Dec 10, 2018 at 06:06:30PM +0100, Damien Mattei wrote:
for now i'm here:
getBD :: Connection -> String -> Float getBD conn name = noBDfp where qry_head = "select `N° BD` from sidonie.Coordonnées where Nom = ?" :: Query -- bd_rows = -- do -- local_bd_rows <- query conn qry_head (Only (name::String)) -- return local_bd_rows bd_rows :: IO [Only Text] bd_rows = query conn qry_head (Only (name::String)) noBDtxt :: [Text] noBDtxt = fromOnly (Prelude.head bd_rows) noBDstr :: String noBDstr = Text.unpack noBDtxt :: String noBDfp = read $ noBDstr :: Float
Okay, I think I understand how your code is structured now. The point to recognize is that bd_rows has type IO [Only Text], which is not the same type as [Only Text]. Prelude.head has the type [a] -> a, and so it can’t be used on bd_rows as-is. Fortunately, being a monad, IO has an instance of Functor for free, and we can go from
head :: [Only Text] -> Only Text
to
fmap head :: IO [Only Text] -> IO (Only Text)
which takes an IO operation returning [Only Text] and applies head to its result, giving an IO operation returning an Only Text.
Can you see how the IO monad follows you through everything that uses its result? If you rewrite noBDtxt as
noBDtxt :: IO [Text] noBDtxt = fmap (fromOnly . Prelude.head) bd_rows
then noBDstr has to be rewritten in a similar way, and so on through to the final result, giving the main function a type of Connection -> String -> IO Float.
A lot of the functions in your where clause can be amalgamated, for example by combining noBDtxt and noBDstr as
noBDstr = fmap (Text.unpack . fromOnly . Prelude.head)
Similarly, getBD takes the result of noBDfp and returns it unaltered, so why not just write
getBD = fmap read noBDstr
?
Let me know if you would like me to explain anything in this message in more detail.
Regards,
Seph
-- Damien.Mattei@unice.fr, Damien.Mattei@oca.eu, UNS / OCA / CNRS

On Tue, Dec 11, 2018 at 04:54:24PM +0100, Damien Mattei wrote:
but the question rest entire :how can i get the loat number from all this?
i have a Main that looks like this:
main :: IO () --main :: Int main =
do conn <- connect defaultConnectInfo { connectHost = "moita", connectUser = "mattei", connectPassword = "sidonie2", connectDatabase = "sidonie" }
-- first we get the N°BD from sidonie
let name = "A 20"
let noBD_IO = getBD conn name
-- putStrLn $ show $ read $ Text.unpack noBD_IO
close conn
print "Exit."
Within a do block, ‘let’ statements are for pure values, while for monadic ones you bind a variable with <-, for example with noBD <- getBD conn name whatever This is do-notation, which desugars to getBD conn name >>= \noBD -> whatever In this context, >>= has type signature (>>=) :: IO a -> (a -> IO b) -> IO b In fact it works for any monad, but let’s stick to IO for now. If we look at this function type a bit, we see that it takes a monadic computation and feeds it into a function that takes a _pure_ value. In this case the function in question is your print statement: putStrLn . show :: Show a => a -> IO () (There is actually a builtin function called print that does exactly this.) Its input type is a, not IO a, so the result of getBD can’t be used as-is, but >>= (pronounced ‘bind’) enables the return value of the IO computation to be fed into the new function, returning a new monadic computation representing the combination of the two original ones. If you think about it, the ‘inescapable’ nature of the IO monad makes sense: if a function is pure, it can’t have side effects, and therefore it can’t use any data that it has to execute a side effect to get. However, the fact that the main function has a monadic type IO (), combined with the ability to ‘chain’ monadic computations as described above, means that you don’t ever need to escape the IO monad; you can simply ‘pull’ the pure functions you need _into_ the monad instead. If I may make a suggestion, I would avoid using do-notation at all until you’re a bit more comfortable with how monadic computations work, and how Haskell handles IO. To someone used to imperative programming, it can be more confusing that helpful, as it allows you to write something that looks and feels a lot like imperative code but differs from it in crucial ways. Get comfortable with using the monadic operators >> and >>= directly, and only then switch back to do-notation. Or don’t—personally I prefer not to use do-notation at all. Regards, Seph -- Seph Shewell Brockway, BSc MSc (Glas.)

thank you a lot Seph for all those explanations, i read them carefully and finally come to this: getBD conn name >>= \noBD -> ((putStrLn . show) noBD) that print it on the screen in main but it remains a last step ,how can get it in a Float variable? Damien Le 11/12/2018 20:27, Seph Shewell Brockway a écrit :
On Tue, Dec 11, 2018 at 04:54:24PM +0100, Damien Mattei wrote:
but the question rest entire :how can i get the loat number from all this?
i have a Main that looks like this:
main :: IO () --main :: Int main =
do conn <- connect defaultConnectInfo { connectHost = "moita", connectUser = "mattei", connectPassword = "sidonie2", connectDatabase = "sidonie" }
-- first we get the N°BD from sidonie
let name = "A 20"
let noBD_IO = getBD conn name
-- putStrLn $ show $ read $ Text.unpack noBD_IO
close conn
print "Exit."
Within a do block, ‘let’ statements are for pure values, while for monadic ones you bind a variable with <-, for example with
noBD <- getBD conn name whatever
This is do-notation, which desugars to
getBD conn name >>= \noBD -> whatever
In this context, >>= has type signature
(>>=) :: IO a -> (a -> IO b) -> IO b
In fact it works for any monad, but let’s stick to IO for now. If we look at this function type a bit, we see that it takes a monadic computation and feeds it into a function that takes a _pure_ value. In this case the function in question is your print statement:
putStrLn . show :: Show a => a -> IO ()
(There is actually a builtin function called print that does exactly this.) Its input type is a, not IO a, so the result of getBD can’t be used as-is, but >>= (pronounced ‘bind’) enables the return value of the IO computation to be fed into the new function, returning a new monadic computation representing the combination of the two original ones.
If you think about it, the ‘inescapable’ nature of the IO monad makes sense: if a function is pure, it can’t have side effects, and therefore it can’t use any data that it has to execute a side effect to get. However, the fact that the main function has a monadic type IO (), combined with the ability to ‘chain’ monadic computations as described above, means that you don’t ever need to escape the IO monad; you can simply ‘pull’ the pure functions you need _into_ the monad instead.
If I may make a suggestion, I would avoid using do-notation at all until you’re a bit more comfortable with how monadic computations work, and how Haskell handles IO. To someone used to imperative programming, it can be more confusing that helpful, as it allows you to write something that looks and feels a lot like imperative code but differs from it in crucial ways. Get comfortable with using the monadic operators >> and >>= directly, and only then switch back to do-notation. Or don’t—personally I prefer not to use do-notation at all.
Regards,
Seph
-- Damien.Mattei@unice.fr, Damien.Mattei@oca.eu, UNS / OCA / CNRS
participants (2)
-
Damien Mattei
-
Seph Shewell Brockway