Fwd: [Haskell-beginners] monad and variable result

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Fwd: [Haskell-beginners] monad and variable result

Damien Mattei
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 <[hidden email]>
Répondre à : The Haskell-Beginners Mailing List - Discussion of
primarily beginner-level topics related to Haskell <[hidden email]>
Pour : The Haskell-Beginners Mailing List - Discussion of primarily
beginner-level topics related to Haskell <[hidden email]>

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?

note the goal is to do the same thing of my main function that works :

main :: IO ()
--main :: Int
main =

  do
    conn <- connect defaultConnectInfo
      { connectHost = "moita",
        connectUser = "mattei",
        connectPassword = "******",
        connectDatabase = "sidonie" }


-- we get all the Double Stars that have angular distance superior to a
threshold of 1 second = 0.000278 degree

    rows <- query_ conn "SELECT Nom,distance FROM AngularDistance WHERE
distance > 0.000278"

    forM_ rows $ \(name,distance) ->
      putStrLn $  Text.unpack name ++ " " ++ show (distance :: Double)


-- we will get the Durchmusterung Number BD from Sidonie and WDS and
compare them for a given name
-- Warning: there could be multiple result in WDS for a given entry name
(due to components)

-- first we get the N°BD from sidonie

    let name = "A    20"
--    let qry = "select `N° BD` from Coordonnées where Nom = " ++ name

    let qry_head = "select `N° BD` from sidonie.Coordonnées where Nom =
?" :: Query

--    bd_rows <- query_ conn "select `N° BD` from sidonie.Coordonnées
where Nom = 'A    20'"

    bd_rows <- query conn qry_head (Only (name::String))

    putStrLn $ show bd_rows
    putStrLn $ show name

    let resLst = Prelude.map fromOnly bd_rows

    let noBDtxt = fromOnly (Prelude.head bd_rows) :: Text
--    let noBD2 =  _ (Prelude.head bd_rows)

    putStrLn $ show resLst

    putStrLn $ show noBDtxt

    forM_ bd_rows $ \(Only a) ->
      putStrLn $  Text.unpack a

    let noBDstr = Text.unpack noBDtxt :: String
    let noBDfp = read $ noBDstr :: Float

    putStr "noBDfp ="
    (putStrLn (show noBDfp))

    close conn

    print "Exit."


for now i have errors in the function:

Prelude> :load UpdateSidonie
[1 of 1] Compiling Main             ( UpdateSidonie.hs, interpreted )

UpdateSidonie.hs:47:28: error:
    • Ambiguous type variable ‘r0’ arising from a use of ‘query’
      prevents the constraint ‘(QueryResults r0)’ from being solved.
      Relevant bindings include
        bd_rows :: IO [r0] (bound at UpdateSidonie.hs:46:9)
      Probable fix: use a type annotation to specify what ‘r0’ should be.
      These potential instances exist:
        instance Result a => QueryResults (Only a)
          -- Defined in ‘Database.MySQL.Simple.QueryResults’
        instance (Result a, Result b) => QueryResults (a, b)
          -- Defined in ‘Database.MySQL.Simple.QueryResults’
        instance (Result a, Result b, Result c) => QueryResults (a, b, c)
          -- Defined in ‘Database.MySQL.Simple.QueryResults’
        ...plus 21 others
        (use -fprint-potential-instances to see them all)
    • In a stmt of a 'do' block:
        local_bd_rows <- query conn qry_head (Only (name :: String))
      In the expression:
        do local_bd_rows <- query conn qry_head (Only (name :: String))
           return local_bd_rows
      In an equation for ‘bd_rows’:
          bd_rows
            = do local_bd_rows <- query conn qry_head (Only (name ::
String))
                 return local_bd_rows
   |
47 |           local_bd_rows <- query conn qry_head (Only (name::String))
   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.



--
[hidden email], [hidden email], UNS / OCA / CNRS
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: [Haskell-beginners] monad and variable result

Seph Shewell Brockway
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.)
_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: [Haskell-beginners] monad and variable result

Damien Mattei
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
>

--
[hidden email], [hidden email], 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.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: [Haskell-beginners] monad and variable result

Seph Shewell Brockway
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.)
_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: [Haskell-beginners] monad and variable result

Damien Mattei
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
>

--
[hidden email], [hidden email], 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.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: [Haskell-beginners] monad and variable result

Seph Shewell Brockway
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.)
_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: [Haskell-beginners] monad and variable result

Damien Mattei
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
>

--
[hidden email], [hidden email], 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.