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