Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: joining lists sharing multiple type classes (Nick Vanderweit)
2. Re: joining lists sharing multiple type classes
(Christopher Howard)
3. Re: Warp and Yesod benchmark puzzle (Felipe Almeida Lessa)
4. Re: Warp and Yesod benchmark puzzle (Lorenzo Bolla)
5. Re: Warp and Yesod benchmark puzzle (Krzysztof Skrz?tnicki)
----------------------------------------------------------------------
Message: 1
Date: Fri, 31 Aug 2012 15:13:41 -0600
From: Nick Vanderweit <[email protected]>
Subject: Re: [Haskell-beginners] joining lists sharing multiple type
classes
To: [email protected]
Message-ID: <1544399.PW3MRytGsC@euler>
Content-Type: text/plain; charset="us-ascii"
It's not that your syntax is off, but rather that what you're trying to do
doesn't really make sense in the Haskell type system. Lists are by nature
parameterized over a single type. It is possible via existential types to have
a list over a polymorphic type like:
exists a. (Locatable a, Animation a) => a
but this is doubtfully what you want. It suffers from the fact that, for a
given list entry, you don't actually know what its type is, and so you can't
do anything really useful here.
So basically: you can't have two kinds of data types in a list. What you
probably want is a data type, like:
data Object = Star ... | Asteroid ...
That is, rather than having two types that you're trying to put in a list,
have one type with two data constructors. Then you *can* store them together,
and write functions that operate via pattern matching on the various
constructors. Hope that helps.
Nick
On Friday, August 31, 2012 11:34:40 AM Christopher Howard wrote:
> Hi. I've got two data structures, Star and Asteroid (eventually I'll
> make more) that both belong to the following type classes: Locatable,
> and Animation. I wanted to do something like so in part of the code:
>
> code:
> --------
> let stars = ... in -- of type [Star]
> let asteroids = ... in -- of type [Asteroid]
> let visibleObjects = do visibleObject <- (stars ++ asteroids)
> ... -- prep each object for graphics system
> -- using funcs from both type classes
> ... -- feed visibleObjects to graphics system
> --------
>
> However, this does not work because the two lists are not automatically
> downgraded when joined together by (++). The compiler complains about
> "asteroids" not being of type [Star]. What is the simplest way to do
> what I am trying to do? I tried this, but I think my syntax is off:
>
> code:
> --------
> let visibleObjects =
> do visibleObject <- ((stars :: [(Locatable a, Animation a) => a)
> ++ (asteroids :: [(Locatable a, Animation a) => a)
> )
> --------
>
> Compiler complains about "Illegal polymorphic or qualified type".
------------------------------
Message: 2
Date: Fri, 31 Aug 2012 13:43:53 -0800
From: Christopher Howard <[email protected]>
Subject: Re: [Haskell-beginners] joining lists sharing multiple type
classes
To: Haskell Beginners <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
On 08/31/2012 12:16 PM, Sergey Mironov wrote:
> Yes, you can't concat [Star] and [Asteroid] because they are of different
> type.
> Lets assume that Animation is defined as follows
>
> class Animation a where
> feed :: GraphicSystem -> a -> IO () -- feeds a to graphic system
>
> and we have
>
> instance Animation Star where ...
> instance Animation Asteroid where ...
>
> than we can do
>
> game_cycle :: ([Star],[Asteroid]) -> GraphicSystem -> IO ()
> game_cycle world@(stars, asteroids) gs = do
> mapM (feed gs) stars
> mapM (feed gs) asteroids
> return ()
>
This would probably work, though it evades my principle inquiry, i.e.,
how to purposely downgrade multiple types which belong to the same type
classes into a single type.
> but not
>
> game_cycle :: ([Star],[Asteroid]) -> GraphicSystem -> IO ()
> game_cycle world@(stars, asteroids) gs = do
> mapM (feed gs) (stars ++ asteroids) -- type mismatch
> return ()
>
> If you absolutly sure, that you really need a single list of all objects,
> consider using single type for them!
>
> data WorldObject = Star ... | Asteroid ...
>
> Sergey
>
This approach is not modular... some of my types will be quite complex
and I would rather have them as their own separate data types in their
own module, rather than one monstrous type.
Looking into this some more... I think what was actually looking for was
existential quantification. That is, I could define a third type:
code:
--------
data Displayable = forall a. (Locatable a, Animation a) => Displayable a
--------
Then I could map this constructor over the other two lists and
concatenate them. This would allow me to use functions from both type
classes in operations on the list members, provided that I extract the
polymorphic component first. I haven't applied it to my actual code yet,
but here is a sort of test case that compiles:
code:
--------
{-# LANGUAGE ExistentialQuantification #-}
class CA a where
f :: a -> Double
class CB a where
g :: a -> Integer
data D1 = D1 Integer
data D2 = D2 Integer
instance CA D1 where
f (D1 x) = fromInteger x + 2.0
instance CB D1 where
g (D1 x) = x + 3
instance CA D2 where
f (D2 x) = fromInteger x + 3.0
instance CB D2 where
g (D2 x) = x + 1
data E = forall a. (CA a, CB a) => E a
d1 = map E [D1 23]
d2 = map E [D2 4]
l = d1 ++ d2
r :: E -> Double
r (E x) = fromInteger (g x) + f x
result = map r l
*Main> :load "/scratch/cmhoward/test0/plist.hs"
[1 of 1] Compiling Main ( /scratch/cmhoward/test0/plist.hs,
interpreted )
Ok, modules loaded: Main.
*Main> result
[51.0,12.0]
--------
Though, I'm not sure if that is simpler than your first suggestion in
this particular case. But it is certainly more interesting!
--
frigidcode.com
indicium.us
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 554 bytes
Desc: OpenPGP digital signature
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20120831/4e59aaa2/attachment-0001.pgp>
------------------------------
Message: 3
Date: Fri, 31 Aug 2012 22:13:20 -0300
From: Felipe Almeida Lessa <[email protected]>
Subject: Re: [Haskell-beginners] Warp and Yesod benchmark puzzle
To: Lorenzo Bolla <[email protected]>
Cc: [email protected], [email protected]
Message-ID:
<CANd=OGGF5pMdD0Qf-=0vh-CBe=j-q5iba7ukdc7qslkrjb2...@mail.gmail.com>
Content-Type: text/plain; charset=UTF-8
[Forwarding to Yesod's mailing list as well. I'll copy all of the
original text below for those who aren't on haskell-beginners.]
On Fri, Aug 31, 2012 at 11:24 AM, Lorenzo Bolla <[email protected]> wrote:
> Hi all,
>
> This is a question specific to the Yesod framework, but simple enough
> (I hope) to be considered a beginner question...
>
> I am puzzled by the performance of these two very simple web-servers,
> one written in Warp and another written in Yesod:
>
> === YESOD ===
>
> {-# LANGUAGE TypeFamilies, QuasiQuotes, MultiParamTypeClasses,
> TemplateHaskell #-}
> import Yesod
>
> data HelloWorld = HelloWorld
>
> mkYesod "HelloWorld" [parseRoutes|
> / HomeR GET
> |]
>
> instance Yesod HelloWorld
>
> getHomeR :: Handler RepHtml
> getHomeR = defaultLayout [whamlet|$newline always
> Hello World!
> |]
>
> main :: IO ()
> -- main = warpDebug 3000 HelloWorld
> main = warp 3000 HelloWorld
>
> === WARP ===
>
> {-# LANGUAGE OverloadedStrings #-}
>
> import Network.Wai
> import Network.HTTP.Types
> import Network.Wai.Handler.Warp (run)
> import Data.ByteString.Lazy.Char8 ()
>
> app :: Application
> app _ = return $ responseLBS
> status200
> [("Content-Type", "text/html")]
> "Hello, Warp!"
>
> main :: IO ()
> main = do
> putStrLn "http://localhost:8080/"
> run 8080 app
>
> ===
>
> I've tested both using httperf:
> $> httperf --hog --client=0/1 --server=localhost --port=3000 --uri=/
> --rate=1000 --send-buffer=4096 --recv-buffer=16384 --num-conns=100
> --num-calls=100 --burst-length=20
>
> and I got very different results:
>
> YESOD: Request rate: 4048.0 req/s (0.2 ms/req)
> WARP: Request rate: 33656.2 req/s (0.0 ms/req)
>
> Now, I understand that Yesod is expected to be slower than the "raw"
> Warp, but I wasn't expecting a 10x slowdown, especially for such a
> trivial Yesod app (no db, no auth, etc.).
>
> [
> Compilation command was: ghc -Wall -O2 --make yesod.hs
> $ yesod version
> yesod-core version:1.1.0
> ]
>
> What is going on?
>
> Thanks,
> L.
This is actually a rather tricky and interesting question =).
My knee-jerk reaction is "profile!". Profiling will give you more
clues about where the time is being spent.
As Bryce said, you're using defaultLayout and Hamlet, which should
slow things down. Also, you're implicitly using clientsession, you
may try setting makeSessionBackend [1] to 'const $ return Nothing' and
see what kind of performance you get.
Cheers!
[1]
http://hackage.haskell.org/packages/archive/yesod-core/1.1.1.1/doc/html/Yesod-Core.html#v:makeSessionBackend
--
Felipe.
------------------------------
Message: 4
Date: Sat, 1 Sep 2012 09:37:53 +0100
From: Lorenzo Bolla <[email protected]>
Subject: Re: [Haskell-beginners] Warp and Yesod benchmark puzzle
Cc: [email protected], [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8
On Fri, Aug 31, 2012 at 10:13:20PM -0300, Felipe Almeida Lessa wrote:
> [Forwarding to Yesod's mailing list as well. I'll copy all of the
> original text below for those who aren't on haskell-beginners.]
>
> On Fri, Aug 31, 2012 at 11:24 AM, Lorenzo Bolla <[email protected]> wrote:
> > Hi all,
> >
> > This is a question specific to the Yesod framework, but simple enough
> > (I hope) to be considered a beginner question...
> >
> > I am puzzled by the performance of these two very simple web-servers,
> > one written in Warp and another written in Yesod:
> >
> > === YESOD ===
> >
> > {-# LANGUAGE TypeFamilies, QuasiQuotes, MultiParamTypeClasses,
> > TemplateHaskell #-}
> > import Yesod
> >
> > data HelloWorld = HelloWorld
> >
> > mkYesod "HelloWorld" [parseRoutes|
> > / HomeR GET
> > |]
> >
> > instance Yesod HelloWorld
> >
> > getHomeR :: Handler RepHtml
> > getHomeR = defaultLayout [whamlet|$newline always
> > Hello World!
> > |]
> >
> > main :: IO ()
> > -- main = warpDebug 3000 HelloWorld
> > main = warp 3000 HelloWorld
> >
> > === WARP ===
> >
> > {-# LANGUAGE OverloadedStrings #-}
> >
> > import Network.Wai
> > import Network.HTTP.Types
> > import Network.Wai.Handler.Warp (run)
> > import Data.ByteString.Lazy.Char8 ()
> >
> > app :: Application
> > app _ = return $ responseLBS
> > status200
> > [("Content-Type", "text/html")]
> > "Hello, Warp!"
> >
> > main :: IO ()
> > main = do
> > putStrLn "http://localhost:8080/"
> > run 8080 app
> >
> > ===
> >
> > I've tested both using httperf:
> > $> httperf --hog --client=0/1 --server=localhost --port=3000 --uri=/
> > --rate=1000 --send-buffer=4096 --recv-buffer=16384 --num-conns=100
> > --num-calls=100 --burst-length=20
> >
> > and I got very different results:
> >
> > YESOD: Request rate: 4048.0 req/s (0.2 ms/req)
> > WARP: Request rate: 33656.2 req/s (0.0 ms/req)
> >
> > Now, I understand that Yesod is expected to be slower than the "raw"
> > Warp, but I wasn't expecting a 10x slowdown, especially for such a
> > trivial Yesod app (no db, no auth, etc.).
> >
> > [
> > Compilation command was: ghc -Wall -O2 --make yesod.hs
> > $ yesod version
> > yesod-core version:1.1.0
> > ]
> >
> > What is going on?
> >
> > Thanks,
> > L.
>
> This is actually a rather tricky and interesting question =).
>
> My knee-jerk reaction is "profile!". Profiling will give you more
> clues about where the time is being spent.
>
> As Bryce said, you're using defaultLayout and Hamlet, which should
> slow things down. Also, you're implicitly using clientsession, you
> may try setting makeSessionBackend [1] to 'const $ return Nothing' and
> see what kind of performance you get.
>
> Cheers!
>
> [1]
> http://hackage.haskell.org/packages/archive/yesod-core/1.1.1.1/doc/html/Yesod-Core.html#v:makeSessionBackend
>
> --
> Felipe.
Good catch Felipe!
It looks like `makeSessionBackend` is horribly slow... These are the numbers on
my box:
Warp
10250 req/s
Yesod
hamlet: 848 req/s
no-hamlet: 940 req/s (getHomeR = return ? RepPlain ? toContent $ "Hello
World!")
no-session: 8000 req/s (makeSessionBackend = const $ return Nothing)
L.
--
Lorenzo Bolla
http://lbolla.info
------------------------------
Message: 5
Date: Sat, 1 Sep 2012 11:33:35 +0200
From: Krzysztof Skrz?tnicki <[email protected]>
Subject: Re: [Haskell-beginners] Warp and Yesod benchmark puzzle
To: Lorenzo Bolla <[email protected]>
Cc: [email protected], [email protected]
Message-ID:
<cam7aevhrksxhszenrikpewdy_sy8zoxy9j2pa5wxzrzjsfc...@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"
makeSessionBackend calls "getKey" from clientsession:
http://hackage.haskell.org/packages/archive/clientsession/0.8.0/doc/html/src/Web-ClientSession.html#getKey
Looking at that function no wonder it is a bottleneck:
-- | Get a key from the given text file.---- If the file does not
exist or is corrupted a random key will-- be generated and stored in
that file.getKey :: FilePath -- ^ File name where key is stored.
-> IO Key -- ^ The actual key.getKey keyFile = do exists
<- doesFileExist keyFile if exists then S.readFile keyFile
>>= either (const newKey) return . initKey else newKey where
newKey = do (bs, key') <- randomKey S.writeFile keyFile
bs return key'
Plenty of syscalls, reading and parsing the same file over and over again.
Perhaps the default should be to store the key within the foundation
datatype at startup?
Best regards,
Krzysztof Skrz?tnicki
On Sat, Sep 1, 2012 at 10:37 AM, Lorenzo Bolla <[email protected]> wrote:
> On Fri, Aug 31, 2012 at 10:13:20PM -0300, Felipe Almeida Lessa wrote:
> > [Forwarding to Yesod's mailing list as well. I'll copy all of the
> > original text below for those who aren't on haskell-beginners.]
> >
> > On Fri, Aug 31, 2012 at 11:24 AM, Lorenzo Bolla <[email protected]>
> wrote:
> > > Hi all,
> > >
> > > This is a question specific to the Yesod framework, but simple enough
> > > (I hope) to be considered a beginner question...
> > >
> > > I am puzzled by the performance of these two very simple web-servers,
> > > one written in Warp and another written in Yesod:
> > >
> > > === YESOD ===
> > >
> > > {-# LANGUAGE TypeFamilies, QuasiQuotes, MultiParamTypeClasses,
> > > TemplateHaskell #-}
> > > import Yesod
> > >
> > > data HelloWorld = HelloWorld
> > >
> > > mkYesod "HelloWorld" [parseRoutes|
> > > / HomeR GET
> > > |]
> > >
> > > instance Yesod HelloWorld
> > >
> > > getHomeR :: Handler RepHtml
> > > getHomeR = defaultLayout [whamlet|$newline always
> > > Hello World!
> > > |]
> > >
> > > main :: IO ()
> > > -- main = warpDebug 3000 HelloWorld
> > > main = warp 3000 HelloWorld
> > >
> > > === WARP ===
> > >
> > > {-# LANGUAGE OverloadedStrings #-}
> > >
> > > import Network.Wai
> > > import Network.HTTP.Types
> > > import Network.Wai.Handler.Warp (run)
> > > import Data.ByteString.Lazy.Char8 ()
> > >
> > > app :: Application
> > > app _ = return $ responseLBS
> > > status200
> > > [("Content-Type", "text/html")]
> > > "Hello, Warp!"
> > >
> > > main :: IO ()
> > > main = do
> > > putStrLn "http://localhost:8080/"
> > > run 8080 app
> > >
> > > ===
> > >
> > > I've tested both using httperf:
> > > $> httperf --hog --client=0/1 --server=localhost --port=3000 --uri=/
> > > --rate=1000 --send-buffer=4096 --recv-buffer=16384 --num-conns=100
> > > --num-calls=100 --burst-length=20
> > >
> > > and I got very different results:
> > >
> > > YESOD: Request rate: 4048.0 req/s (0.2 ms/req)
> > > WARP: Request rate: 33656.2 req/s (0.0 ms/req)
> > >
> > > Now, I understand that Yesod is expected to be slower than the "raw"
> > > Warp, but I wasn't expecting a 10x slowdown, especially for such a
> > > trivial Yesod app (no db, no auth, etc.).
> > >
> > > [
> > > Compilation command was: ghc -Wall -O2 --make yesod.hs
> > > $ yesod version
> > > yesod-core version:1.1.0
> > > ]
> > >
> > > What is going on?
> > >
> > > Thanks,
> > > L.
> >
> > This is actually a rather tricky and interesting question =).
> >
> > My knee-jerk reaction is "profile!". Profiling will give you more
> > clues about where the time is being spent.
> >
> > As Bryce said, you're using defaultLayout and Hamlet, which should
> > slow things down. Also, you're implicitly using clientsession, you
> > may try setting makeSessionBackend [1] to 'const $ return Nothing' and
> > see what kind of performance you get.
> >
> > Cheers!
> >
> > [1]
> http://hackage.haskell.org/packages/archive/yesod-core/1.1.1.1/doc/html/Yesod-Core.html#v:makeSessionBackend
> >
> > --
> > Felipe.
>
> Good catch Felipe!
> It looks like `makeSessionBackend` is horribly slow... These are the
> numbers on
> my box:
>
> Warp
> 10250 req/s
>
> Yesod
> hamlet: 848 req/s
> no-hamlet: 940 req/s (getHomeR = return ? RepPlain ? toContent $
> "Hello World!")
> no-session: 8000 req/s (makeSessionBackend = const $ return Nothing)
>
> L.
>
> --
> Lorenzo Bolla
> http://lbolla.info
>
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://www.haskell.org/pipermail/beginners/attachments/20120901/44f96946/attachment.htm>
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 51, Issue 1
****************************************