Discussion:
[Haskell-cafe] Fwd: [Haskell-beginners] monad and variable result
Seph Shewell Brockway
2018-12-10 16:19:39 UTC
Permalink
Hi Damien,
have some code that works but want to put it in a simple function
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.)
Seph Shewell Brockway
2018-12-10 18:56:36 UTC
Permalink
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.)
Loading...