--- Log opened Sun Mar 01 00:00:28 2009
00:00 < rovar> sure.. reliable UDP just has a few bennies over unreliable besides ACKs. specifically windowing and congestion control
00:01 < jsn> maybe, but we have to throw out old requests anyways
00:01 < jsn> if they don't make their round, they're dead
00:01 < jsn> i mean, of course you want them to get there if they can
00:01 < jsn> but the system needs to be independent of that :)
00:01 < jsn> otherwise, it's not safe
00:02 < rovar> so when a change occurs, that changeset is broadcast immediately, but voting on all changesets that occured happens at strict intervals, correct?
00:03 < jsn> right
00:06 < rovar> so assuming a website is getting 20 reqs/sec it distributes those requests to 5 machines, each request is a write on a distinct key,
00:07 < rovar> this change set amounts to 100 bytes of data.
00:16 < rovar> so the number of Bps is (((r/n) * (n - 1)) * change-size) + (2  * r * n * (proposal-vote-size))
00:16 < rovar> assuming that each changeset is voted on individually.
00:17 < rovar> actually.. i suppose that that could be optimized to have a single message to indicate acceptance/rejection of all changesets currently proposed
00:22 < rovar> assuming a vote-per-request, because that's easier to quantify.. a system receiving 20 requests per second for a 100b change set to a ring of 5 servers and a 20 byte vote message
00:23 < rovar> per machine that would be approx 5.6kBps
00:24 < rovar> bleh.. that's not exactly right either.. i should forget about per machine and focus on net wide
00:34 < rovar> intuitively, I would suppose that this process could be more optimal than Spread + data logging by virtue of the fact that the message reliability is the data reliability.
00:35 < rovar> failures in spread would be handled separately from failures in the data distribution algorithm..
00:36 < rovar> therefore, message failures in the quorum don't necessarily mean a failure to sync data for all systems, and assuming we could implement a proper fail/recovery scheme, it could be much more fault tolerant
00:37 < rovar> i don't even know if you're still around, am mostly thinking out loud
00:46 < rovar> jsn, so how are conflicts resolved? I'm thinking of the basic case of a hit counter, where the new value supplied depends on the previous value.
00:46 < rovar> so the customer reads, then writes,  and hopes that read/write was atomic
00:47 < rovar> assuming all members are updating this variable at the same time, the 1st changeset in the quorum wins, but how do the remaining nodes resolve their conflict?
00:56 < rovar> one obvious solution to me is to broadcast the function, not the updated state.
02:11 < h_buildbot> Build for ghc-6.8.3 OK. Test suite ran. 15/77 test cases failed. Check http://buildbot.happstack.com/ for details.
02:18 < stepcut> we should add this link to the wiki or something,  http://groups.google.com/group/HAppS/browse_thread/thread/c6a73045a8dbc9d5?pli=1
02:19 < h_buildbot> Build for ghc-6.10.1 OK. Test suite ran. 15/77 test cases failed. Check http://buildbot.happstack.com/ for details.
02:40 < rovar> yea, the more i think about it, the more i like making events be functions
02:41 < rovar> not updated state
03:36 < mae> jsn: What is your real name so I can blog about the papers you are working on, as I understand it, three right? consistent logging, sharding, and membership?
03:37 < mae> jsn: i come from a ruby on rails background :) my heart feels sad for you.
03:40 < mae> rovar: what is your real name?
03:41 < rovar> Rick Richardson
03:47 < mae> 10-4
03:48 < mae> exciting stuff! :)
03:48 < mae> glad to have more help
03:59 < rovar> I am not sure how much help I'll be, my availability seems to be limited to weekends and my haskell skills aren't great
03:59 < rovar> i work a lot
03:59 < rovar> unfortunately, with C++ primarily
11:32 < oshyshko> Is there any small example of HAppS-State usage with basic list/add/remove operations?
11:33 < oshyshko> I have found http://bluebones.net/2007/09/simple-haskell-web-programming-with-happs/ but it seems to be obsolete.
11:34 < stepcut> oshyshko: um...
11:36 < stepcut> oshyshko: there is happstack/happstack/template/project
11:37 < stepcut> oshyshko: list/add/remove only make sense in for some datatypes. The basic operations are really just query (which could be used for listing), and update (which could be used for add/remove)
11:40 < oshyshko> stepcut: okay. Where is happstack/happstack/template/project ?
11:40 < stepcut> oshyshko: it's in the happstack darcs repo
11:40 < stepcut> oshyshko: are you using happstack 0.1 ?
11:41 < oshyshko> stepcut: I installed happs-tutrial with deps: HAppS-Server 0.9.3 and friends.
11:42 < oshyshko> stepcut: from cabal
11:42 < stepcut> oshyshko: ah
11:42  * stepcut ponders
11:44 < stepcut> oshyshko: you might consider upgrading to the latest version of happstack from darcs. 0.2 is going to be released around Mar 4, but the repo is pretty much stablized no
11:44 < stepcut> now
11:45 < stepcut> oshyshko: there is a lot of work to improve the documentation, add tutorials and example, etc. But it is based around the latest happstack -- which is mostly the same but a little bit different.
11:52 < oshyshko> stepcut: okay, I will darcs-get the new happstack and migrate to it
11:53 < stepcut> oshyshko: sweet!
12:37 < mae> top o the morning to yall
12:37 < mae> damn 36 users
12:37 < mae> weren't we like 20ish a month  ago?
12:42 < stepcut> :)
12:42 < oshyshko> A question about template project: function getEntries: gb <- query ReadGuestBook looks good and simple enough...
12:43 < mae> how does it render?
12:44 < mae> gb is a type Guestbook which is of typeclass ToMessage, so the http server knows how to render that type.
12:44 < mae> if you lookin AppView.hs
12:44 < oshyshko> but in order to make it work AppState.hs supplies nearly 20 lines of code, e.g mkMethods, readGuestBook, AppState, instance, version etc... totalling in 60 lines
12:45 < oshyshko> yeah, I understand about AppView.hs
12:45 < mae> well, strictlyspeaking, AppState is not *required*
12:46 < mae> AppState is kind of like the root container objecct for the app
12:46 < mae> so in the future you can add more data types to it
12:46 < mae> but right now it just has the guestbook
12:46 < mae> instead of having AppState, you could have just [GuestBookEntry]
12:47 < rovar> i'm mucking with a direct REST->state adapter.
12:47 < mae> but then this wouldn't be very flexible in the future
12:47 < rovar> adaptor?
12:47 < mae> rovar: neat
12:47 < rovar> meh
12:48 < mae> rovar: btw earlier, you are helping just by having the discussions with jsn, to help him prove the correctness of his algorith
12:48 < mae> m *
12:48 < rovar> currently it runs in the controller.. however, would this not be awesome as a 'plugin' that did translations without having to have any controller code?
12:48 < oshyshko> But is there a way to inline/reduce it? 60 lines. Ouch! E.g.: getEntries = do gb <- query (undefined::Guestbook) () --- and don't add no queries into AppState.hs - only algerbraic data definitions
12:48 < rovar> because really what you're saying is,  Mr web server, I'd like you to be my model.
12:53 < oshyshko> What I'm trying to tell is: Look, three are types: AppState, GuestBook, GuestBookEntry; two operations: list, add. And 60 lines of code. In Ruby+ActiveRecord that would take 15 lines.
12:54 < oshyshko>  /three are/there are three/
12:54  * stepcut is not real happy about the organization of AppState now that he is looking at it more closely.
12:55 < rovar> oshyshko: it's a 1st whack, it'll get better.. look, on the upside... that operation would take 600 ms to complete, in happstack it takes 10 :P
12:55 < rovar> in rails/active record, that is
12:56 < mae> oshyshko: I don't like the cruftiness of it either, but we are working to make it nicer.
12:56 < mae> oshyshko: the important part, is that it works, now -- and DHH believes in this virtue. Rails has had many years now to become what it is today
12:57 < rovar> mae, actually, I think my  BerkelyDB  $(makeBinary ''Foo)  stuff ends up being the same or less code  :/
12:57 < rovar> no.. State is much more readable than my stuff
13:01 < rovar> anyone: is there an existing standard REST client api for Haskell? If not, I'm about to write one
13:04 < vegai> there's a couchdb client lib, perhaps that has something
13:05 < stepcut> oshyshko: here is a less crufty version of AppState, http://hpaste.org/fastcgi/hpaste.fcgi/view?id=1933#a1933
13:06 < stepcut> oshyshko: about 22 lines, if you don't include the import statements and language pragmas
13:06 < oshyshko> rovar: Yeah, Ruby is slow. But the code is brilliant. I think using Grails/Groovy can have neraly same beaty as Ruby does, but much better speed. And if to replce RDBMS with Prevayler or DB4O, you can that both: cool code + performance. But it is Java o JVM - with all drawbacks, and wish I could have those libs and simplicity in Haskell and I believe some day I will ;)
13:06 < rovar> oshyshko: it's moving that way rapidly. and yea, I was a big Merb proponent for a long time.
13:07 < stepcut> mae: I don't like the way that AppState is setup. Currently the guestbook is dependent on the AppState type -- which does not sense to me. The guestbook should be a separate component that AppState uses
13:07 < oshyshko> stepcut: nice
13:08 < rovar> stepcut, is there a way to indicate which records will be used in the model and implicitly derive* them?
13:08 < rovar> that would help a lot
13:08 < stepcut> oshyshko: also, the deriveSerialize lines are a wart that will hopefull go away someday, in the deriveAll clause you should just be able to put, ''Serialize
13:08 < stepcut> rovar: I don't understand the question
13:09 < stepcut> 'records' and 'model' don't really mean anything to be in the context of happstack
13:10 < stepcut> at the risk of making that code 4 lines longer, GuestBook should be a functor instance :)
13:10 < stepcut> oh, wait, nevermind.
13:13 < rovar> stepcut, you kind of covered it.  I would  actually move that list that deriveAll operates on out of the macro.
13:14 < rovar> but it seems like deriveAll and deriveSerialize could be merged
13:14 < stepcut> rovar: why would you remove the list?
13:15 < rovar> i wouldn't remove it.. I'd move its declaration outside of deriveAll macro, purely for ergonomics
13:15 < rovar> imo, the most important item in AppState is the view of the records used within
13:15 < rovar> they should have big blinking lights around them, not be embedded in cryptic code
13:17 < stepcut> rovar: which list? [''Read, ''Show, ...] ?
13:17 < rovar> [d| data GuestBookEntry ...]
13:18 < rovar> actually.. i'm not really sure that's a real list, I don't knot TH yet
13:18 < rovar> know
13:18 < stepcut> rovar: so you would do, myTypes = [d| data GuestBookEntry ...] ; $(deriveAll [''Read, ''Show, ...] myTypes)
13:18 < stepcut> ?
13:19 < rovar> yea, basically
13:19 < rovar> i'm testing it now.
13:19 < rovar> what is d?
13:20 < stepcut> it turns the declarations inside [d| |] into Template Haskell
13:20 < stepcut> the snippet I just pasted won't actually compile due to staging restrictions unless you define myTypes in one file and the, deriveAll [] myTypes, in a second file
13:21 < rovar> that's fine, as long as myTypes can be defined in AppState.hs and deriveAll can be defined in a module...
13:21 < rovar> but i'm not sure that's possible :/
13:22 < stepcut> I guess...
13:22 < stepcut> the deriveAll clause is basically the same as doing, data MyType = MyType deriving (Read, Show, Eq, Ord), except there are some extra things you can derive.
13:23 < rovar> using rails as a guide for ergonomics (which is rarely a bad idea)  I want to define state and its structure, I don't care what new methods it gives me, I assume it gives me CRUD
13:23 < mae> stepcut: push it up, there is still time :) its just aesthetic cleanup right?
13:24 < rovar> I'm just being nitpicky
13:24 < rovar> but I like my ergonomics
13:24 < mae> rovar: me too
13:24 < mae> stepcut: I don't really like deriveAll, the original version I made doesn't use it.
13:24 < mae> it spits out error messages, and theres no avoiding it
13:25 < mae> because quasiquotation tries to reify the Name(s) and they aren't defined yet
13:25 < mae> TH is sensitive to chronology
13:26 < mae> stepcut: I think it would make more sense to define the types first, and then have like $(deriveAll [''GuestBookEntry, ''GuestBook])
13:26 < mae> if we use standalonederiving
13:26 < mae> we don't have to explicitly derive all that stuff yet
13:26 < mae> in the initial definitions
13:26 < mae> can be done in th
13:26 < mae> then this solves the ugly warnings
13:27 < mae> and doesn't look funky to haskellers that aren't used to TH
13:29 < stepcut> I guess... it has the same number of TH statements.
13:30 < rovar> okay, i have,  http://hpaste.org/fastcgi/hpaste.fcgi/view?id=1934#a1934
13:30 < rovar> my goal would be to not care at all what's in AppState
13:31 < rovar> (also, this doesn't link)
13:32 < oshyshko> rovar: I may guess, readGuestBook and addGuestBookEntry are still valueable?
13:32 < rovar> oshyshko: yes, but i would just trust that they're built to a standard convention
13:33 < stepcut> oshyshko: readGuestBook and addGuestBookEntry are, in fact, the only way to update the stuff in AppModel
13:33 < rovar> src/Main.hs:28:17: Module `AppState' does not export `AppState(..)'
13:33 < rovar> do i need to rebuild?
13:34 < stepcut> rovar: no, just change AppState to GuestBook
13:34 < oshyshko> rovar: well, I have this http://hpaste.org/fastcgi/hpaste.fcgi/view?id=1935#a1935 and my problem as haskell newbee: i can't make it compile ;) because its complex
13:39 < wchogg> Sorry if I missed this, but why do the functions parseCookies & cookiesParser have haddock comments saying "not a supported api"?
13:42 < rovar> stepcut: I'm not sure what you mean
13:43 < stepcut> rovar: when I refactored AppState I dropped the AppState type. So Main needs to import GuestBook instead.
13:44 < rovar> so import AppState (GuestBook)
13:45 < rovar> and stateProxy :: Proxy GuestBook
13:45 < rovar> that worked
13:45 < stepcut> yes
13:45 < stepcut> yes
13:45 < rovar> i rather like this
13:45 < rovar> it would be nice if I could define a list of types and just assume that they get all of the goodies added to them.
13:46 < rovar> get/put/serialize/etc
13:46 < stepcut> rovar: um... that would be like defining a bunch of SQL tables and assuming that all the SQL queries get added...
13:47 < rovar> stepcut, I'd like to think that  it would be defining a bunch of business objects and giving them default CRUD methods
13:48 < rovar> I don't see a lot of point in creating a record for State without the ability to add and read it.
13:48 < rovar> i would guess that would be the rule rather than the exception
13:49 < stepcut> rovar: but, when you add and read it, there are usually a bunch of constraints that must be followed to ensure data integrity
13:49 < mae> rovar: the idea is that if we generalize this into a database, then we lose the explicitness of defining your own accessors. When you define your own accessors, you get to implement your business logic, and they become the entrypoint for your data
13:49 < stepcut> rovar: for example, if you are adding a new user, the UserId needs to be unique
13:49 < mae> in sql there are many ways around your business logic
13:49 < rovar> i agree, that should go in an explicit validator, which the add* command would implicitly use
13:49 < mae> hmm
13:50 < mae> too much magic.
13:50 < stepcut> rovar: but, not all datatypes even have a concept of 'add'
13:50 < rovar> meh.. i suppose
13:50 < mae> there are two types of validation
13:50 < mae> (from sql world)
13:50 < rovar> i do get kind of annoyed at rails' magic sometimes
13:50 < mae> database level, and application level
13:50 < mae> here, we have one kind
13:50 < mae> application level
13:50 < mae> ok sure you have to write the function/event
13:50 < mae> but you only do it once
13:51 < mae> stepcut: so are you converting GuestBook into a component?
13:51 < rovar> okay, you guys have convinced me.
13:51 < stepcut> mae: yes
13:52 < rovar> you may proceed as planned.
13:52 < mae> stepcut: ok
13:52 < mae> rovar: i did rails for about 2 years
13:52 < rovar> coke?
13:52 < mae> hahaha
13:54 < rovar> i'm just now looking at the Component and Dependencies stuff
13:55 < stepcut> rovar: for something like, data HitCounter = HitCounter Integer, you are going to want two methods: getHits :: Query HitCounter Integer, and incHits :: Integer -> Update HitCounter Integer. And incHits will return the updated hit value as well. When you use GetHits and IncHits, you will never even see the internal data-type. In fact, it could change and you would never know it if GetHits and IntHits kept the same interface.
13:57 < rovar> stepcut: sure. I'm on board, you don't need to convince me further :)
13:57 < rovar> I've moved on to defining an appHandler factory for rest that uses the Model :)
13:58 < stepcut> mae: I think maybe we need to clarify the purpose of the project template -- I think it may be attempting to do two conflicting things
14:00 < mae> stepcut: it is?
14:00 < mae> how so?
14:00 < mae> it is meant to be a starting point
14:00 < mae> thats why i named stuff generically
14:01 < stepcut> mae: right
14:01 < mae> most people don't have much clarity on necessarily what their project will end up being eventually
14:01 < mae> so we don't want to burden them with
14:01 < mae> what are you gonna name your component? etc etc
14:01 < stepcut> mae: right
14:01 < mae> hence AppState
14:01 < mae> but it probably sends the wrong message
14:01 < mae> I think it serves both purposes you probably ahve in mind
14:02 < mae> they can easily change the component name from guestbook to MySpace2
14:02 < mae> or whatever
14:02 < rovar> for the case in which you have too many records and accessors to fit in one file
14:02 < mae> but I don't want to take the guestbook to the extreme where the code is *too* clever or concise
14:02 < stepcut> mae: the issue is that the organization that works for a very small application does not scale to even a medium sized application. And, you need to have things setup up properly so that you migration works in a managable way etc.
14:03 < mae> explicitness is good because it is easy to see what is going on
14:03 < mae> stepcut: right, but guestbook is not intended to be a school in scalability 101
14:03 < mae> it is just the first step
14:03 < mae> like "cool it works!"
14:03 < stepcut> mae: a template that gets you started in the wrong direction seems like a good way to lead to frustration
14:03 < mae> (developer gets adrenaline rush)
14:03 < mae> "i'm going to write myspace 2 in happstack!"
14:04 < mae> stepcut: maybe, but many developers don't think like you do :)
14:04 < rovar> and even in version 0.2 it would be more stable than the current Myspace
14:04 < wchogg> Nah, go for MySpace Omega': the Final Social Network
14:04 < stepcut> mae: but, by providing the template, people will assume that it must be the "right way" to do things, since they do not have to experience to know otherwise. Hence they trust the authority of the officially sanctioned template
14:04 < mae> many work off of a develop/test cycle and don't get into much of an engineering mindset
14:05 < rovar> wchogg: I'm rather fond of Myspace Omicron, because hey, wtf?
14:05 < mae> stepcut: there is a balance between individuality and default / blessed methodology to be found here
14:05 < mae> I really don't want to go to the rails extreme
14:05 < mae> we don't want a bunch of fanatics putting on purple nikes ready to ride the comet to space after we poison them
14:05 < rovar> mae, I agree with that, learning how to work the generator is a huge impediment to starting :)
14:06 < rovar> in rails, that is
14:06  * rovar drinks the cool aid.
14:06 < wchogg> rovar : I'll second your motion only if you make "hey, wtf?" the slogan
14:06 < mae> um
14:06 < mae> huge impediment?
14:06 < rovar> done.
14:06 < mae> i thought it made things nice and easy
14:07 < rovar> once you learned how to work it.
14:07 < mae> heh
14:07 < vegai> "We're not saying you can serve eBay from a single server, but..." :)
14:08 < mae> stepcut: go ahead and turn it into a component, clean the code up etc. but don't take the engineering perspective too far, we need the guts exposed so it can serve as an example
14:08 < rovar> the scalaris guys claim serving all of wikipedia from an 8 core xeon.
14:08 < stepcut> mae: because people don't engineer, that seems like all the more reason to give them a framework that could scale, instead of something that definitely won't.
14:09 < rovar> whiddling is good
14:10 < mae> stepcut: we are starting to get into a very subjective / controversial line of conversation now, I don't think that they are necessarily headed towards failure if they start out with some cruft.
14:10 < mae> they can iteratively improve their code as they learn more
14:10 < mae> not everyone grows up to be an astronaut
14:11 < mae> i would say half the internet runs on rubber-bands and old toaster parts, and it seems to do ok
14:11 < mae> hehe
14:11 < mae> (perl is a popular rubber-band)
14:11 < wchogg> I'm with mae, actually.  When I used to do performance analysis for a company I found that it was really silly algorithmic mistakes & not fundamental framework problems that hurt you the most.  Underlying technical bottlenecks can be addressed in time.
14:12 < mae> yeah, human fat-fingering
14:12 < stepcut> mae: I'm just saying we should be careful. People are going to be very hesitant to do things differently than the template does, because they will have a tendency to assume that we did it 'the best way', because obviously we know more than them, so why should they question our methods? Obviously, that is a faulty argument, but it is they way most people are :)
14:12 < wchogg> stepcut : I think we can easily counter that with good docs & a blitzkrieg of examples.
14:13 < mae> stepcut: I agree with you to a certain extent, I agree that the guestbook can become a component etc, because this falls into the "happ(stack) way" tm
14:13 < stepcut> wchogg: right -- and I am saying that the guestbook should be one of those good docs and examples :)
14:13 < mae> stepcut: I guess I am trying to simply point out that we shouldn't write guestbook as if it were a generalized drop-in component for the masses
14:14 < mae> stepcut: we should write it making the assumption that someone will not share this code, it lowers the barriers to entry
14:15 < stepcut> mae: right
14:17 < rovar> what are the current facilities for adding a new controller / state after the app is generated?
14:17 < HugoDaniel1> are you guys planing anything for the haskell hackaton in april ?
14:18 < stepcut> rovar: you can add new Components just by adding new components, nothing special required. If you want to modify existinc state, then you can use the Version + Migrate classes
14:22 < stepcut> mae: one goal would be to provide the template that will provide the lowest barrier to building a small to midsized happstack application which can be deployed in the real world. Something that people can use until they understand the system well enough to come up with own policies. This template would be slightly more complicated than a very simple hello world type application.
14:23 < rovar> guestbook?
14:26 < stepcut> mae: that is where the conflicting goals comes in. I don't think that the template project can simultaneously be a good starting template and the very first happstack application you look at / experiment with. It could be the second program you look at though when you are ready to attempt your first real happstack application...
14:27 < rovar> guys, is there a plan for supporting alternate formats for controller methods?
14:27 < rovar> i.e. json instead of xhtml
14:27 < stepcut> rovar: what is the current format of the controller methods?
14:27 < rovar> or a convention already in place
14:28 < rovar> methodM GET/PUT/etc
14:28 < rovar> there doesn't seem to be an place for a parameter indicating the expected output format
14:29 < rovar> so I would just duplicate a function.
14:29 < rovar> or wrap getEntries in my own selector
14:33 < stepcut> rovar: that is really up to the app developer to decide on what type of structing they want.
14:33 < rovar> righto
14:34 < rovar> didn't know if there was already such a convention
14:34 < stepcut> rovar: in guestbook, the WebT part that generates the response gets to decide everything about the Response
14:35 < stepcut> rovar: but, the WebT could, in fact, just return a custom data type which includes all of the information that is needed, but no presenetation specific stuff. A higher level function could then turn that data into XHTML/JSON/etc
14:35 < stepcut>  
14:35 < rovar> what is WebT?
14:35 < stepcut> rovar: the innermost part of a ServerPart. Conceptually, the ServerPartT stuff handles the routing and analysis of the incoming Request, and then it invokes a WebT part that generates the appropriate response
14:36 < stepcut> rovar: in getEntries,
14:36 < rovar> that uses appHandler ?
14:37 < stepcut> appHandler is a ServerPartT
14:37 < rovar> gotcha
14:37 < rovar> i get it.. i was confused because the types of getEntries/etc aren't explicit
14:38 < rovar> i was going to load it interactively but I need to get it to compile 1st :)
14:39 < stepcut> rovar: yes. I think mae thought that not making the types explicit would make it easier to understand? I would like to see explicit type signatures.
14:39 < rovar> it makes it tough when you're trying to extend it.. but I see both sides
14:39 < rovar> maybe this is another argument for the sample app vs project template
14:42 < rovar> arg
14:43 < mae> stepcut: Well, there are plenty of tutorials out there -- this is supposed to be "easy starting mode" if you want to separate those goals
14:43 < mae> the happstack command could have two options
14:43 < mae> new simple project
14:43 < mae> or new advanced project
14:43 < mae> but this is alot of example code to maintain/keep current
14:43 < mae> unless someone is willing to maintain the "advanced" one for each release, I would rather not go down that road, and leave it to the bloggers :)
14:44 < stepcut> mae: I only see a need for one project at this point in time.
14:45 < mae> stepcut: so keep it simple with a hint of engineering prowess :)
14:45 < stepcut> mae: my intention is to make it as simple as possible but not simpiler
14:45 < stepcut> simpler
14:46 < mae> stepcut: ok :)
14:46 < mae> I gotta get off chat for a bit guys, gotta get some stuff done
14:46 < stepcut> :)
14:46 < mae> hehe
14:46 < mae> ttyl
14:53 < rovar> here's my first hack at it:  it's straightforward, but I suppose it could be prettier.
14:58 < rovar> http://moonpatio.com/fastcgi/hpaste.fcgi/view?id=1674#a1674
14:58 < rovar> i don't know how to redirect to 404
14:58 < rovar> so i render the readme for now
14:58 < stepcut> notFound (toResponse "lol")
14:59 < stepcut> though, I think there is a fancier way to do it now too using default 404 handler response filters
15:00 < rovar> well the whole thing needs to move up into the WebT
15:00 < rovar> or some fancier version of dir could work i suppose
15:01 < jsn_> rovar: i'm sorry to have disappeared yesterday
15:01 < jsn_> interesting, i lost my nick
15:01 < rovar> jsn_: did you register?
15:01 < jsn_> rovar: yes
15:01 < jsn_> rovar: so i need to log out and log back in, i guess
15:02 < rovar> no.. you can recover it from nickserv
15:02 < jsn_> rovar: some IRL conversation came up
15:02 < jsn_> rovar: yes, that is the right way :)
15:02 < rovar> what is this, RL you speak of?
15:02 < jsn_> IRL is in-real-life
15:02 < rovar> go on...
15:03 < jsn_> well, i disappeared rather suddenly, is all
15:03 < rovar> i figured you fell asleep
15:03 < rovar> narcoleptic or somesuch
15:03 < stepcut> my top-level state componets are really boring
15:05 < rovar> i'm trying to come up with a function that could generate a subset of elements for the appHandler list.
15:05 < rovar> the idea is to basically generate a list of dirs that are  /json/method/object/args using my model :)
15:06 < rovar> the methods themselves should be generic as well.
15:06 < stepcut> rovar:  you could use syb-with-class or TH
15:07 < rovar> yea... I knew it would have to go meta :)
15:10 < jsn_> wow, someone stole my nick
15:11 < rovar> now is your opportunity to come up with something very clever.
15:16 < rovar> stepcut, maybe something like this?
15:16 < rovar> appHandler :: ServerPartT IO Response
15:16 < rovar> appHandler = msum $ concat $
15:16 < rovar>   [ createJSONPaths [GuestBook],
15:16 < rovar>     [ methodM GET >> seeOther "/entries" (toResponse ()) -- matches /
15:16 < rovar>     , dir "entries" $ msum[ postEntry, getEntries ]        -- RESTful /entries
15:16 < rovar>     , dir "README" getREADME                             -- StringTemplate example
15:16 < rovar>     , fileServe ["index.html"] "public"                  -- static files
15:17 < rovar>     ]
15:17 < rovar>   ]
15:17 < stepcut> rovar: that could work
15:18 < stepcut> rovar: though it does not provide any way to valid the changes when you post an update via JSON?
15:18 < stepcut> s/valid/validate/
15:20 < rovar> stepcut, it will call the addGuestBookEntry method, which should validate, correct?
15:20 < rovar> solidsnack: not bad
15:20 < solidsnack> hehe
15:20 < rovar> solidsnack: rovarismyhero has a nice ring to it
15:21 < stepcut> rovar: *what* will call the addGuestBookEntrie method? If you POST to /entries, yes. But does createJSONPaths have a way to POST values? or only read them ?
15:23  * stepcut remembers something about trying to make guestbook a component
15:23 < rovar> stepcut: i guess there would be two generic functors , renderJSON Type and processJSON Type which 'know' to call the correct add/get functions
15:23 < solidsnack> turns out i had registered a slightly different nick -- jsnx -- and i made a mistake when configuring my client. jsn is a nick i use on other servers, so i didn't really think about it.
15:23 < solidsnack> then the real jsn showed up after a long, long time
15:24 < solidsnack> i see in the logs that mae asked for my real name?
15:24 < solidsnack> it is Jason Dusek
15:24 < stepcut> rovar: by 'know' I assume that means the programmer tells it what needs to happen explicitly?
15:26 < rovar> can it make an educated guess?
15:27 < stepcut> rovar: how would it know? Let's say that the UserId field needs to be unique?
15:29 < rovar> how about a mapping in the GuestBook component which would map a CRUD method to the actual defined method, or blank if there is none
15:30 < stepcut> CRUD?
15:31 < rovar> create replace update delete
15:33 < stepcut> ah
15:34 < stepcut> rovar: if the data type changes then the API changes as well?
15:38 < stepcut> rovar: In order for createJSONPaths to work, each type that is part of the GuestBook type must have a toJson instance?
15:39 < rovar> stepcut,  yes
15:39 < rovar> it would have to be derived like the other serialization methods
15:43 < rovar> i suppose an explicit alist that could be passed to createJSONPaths would be fine.
15:43 < rovar> or a record
15:44 < rovar> data PersistJSON = {add :: Just addJSONGuestBookEntry,  del :: Nothing ...}
15:57 < stepcut> here is an unsolved problem. If you have a component, such as a guestbook, that you want to embed in your site. The guestbook itself won't know how to render the page headings, etc. It only knows how to render its part of the 'canvas'. So, you need some way to glue the output of the guestbook and the overall site context together
16:09 < rovar> yea, it would be more akin to the XMLGenerator stuffs
16:10 < rovar> to be embedded manually in a larger body of text
16:12 < stepcut> it's mostly a structuring issue. Should the guestbook return a fragment of XML which gets embedded in the larger site by the code that calls the handler. Or, should the code that calls the guestbook handler pass in a callback function like, page :: PageTitle -> GuestBook -> ServerPartT IO Response, that renders the page so that the guestbook program can call it as required.
16:12 < stepcut> Or something else.
16:13 < rovar> i would say A
16:13 < rovar> it more closely matches the current usage patterns
16:13 < rovar> when it comes to rendering objects in html, that is going to be very site specific, whereas something like json or xml is not going to change
16:14 < stepcut> rovar: the problem with A is that not all Requests result in XML that is embedded. sometimes it does a 303 redirect or something else.
16:15 < h_buildbot> Build for ghc-6.8.3 OK. Test suite ran. 16/77 test cases failed. Check http://buildbot.happstack.com/ for details.
16:16 < stepcut> rovar: oops, I meant to say 'a fragment of html'. Then there is a third possibility, which is that the guestbook returns a type like, data GuestbookResponse = Entries (GuestBook) | Redirect String | etc, and the caller decides what to do with that information. Such as render it as HTML, JSON, etc
16:16 < rovar> i see what you're saying
16:17 < stepcut> that allows you to package up all the functionality of your component with out forcing any particular view, or use of HSP vs Text.XHtml, etc
16:17 < stepcut> then you could also opt to provide some default HSP, etc, instances that developers could opt to use
16:17 < rovar> right
16:19 < stepcut> but, in practice, the code for that style is not very pretty -- which makes me thinking something is missing
16:20 < rovar> we've gone past too many levels of abstractions for me
16:20 < rovar> I'm going to implement createJSONPaths and see how to generalize from there :)
16:22 < rovar> Text.JSON is going to be helpful
16:24 < h_buildbot> Build for ghc-6.10.1 OK. Test suite ran. 15/77 test cases failed. Check http://buildbot.happstack.com/ for details.
16:33 < rovar> stepcut: so mkMethods turns addGuestBookEntry into AddGuestBookEntry?
16:34 < rovar> what is the purpose of that?
16:34 < stepcut> rovar: So that you can serialize the AddGuestBookEntry event and save it to disk or send it to the spread network
16:35 < rovar> oh right
16:35 < rovar> awesome
16:35 < rovar> so I don't need those methods for the json accessors
16:36 < stepcut> rovar: depends on how you implement things
16:37 < rovar> it makes sense to me to have addJSONGuestBookEntry to decode then call addGuestBookEntry
16:37 < rovar> or rather AddGuestBookEntry
16:38 < stepcut> yeah...
16:46 < oshyshko> rovar: Have you tried CouchDB? JSON-over-HTTP access API, views created from JS.
16:51 < rovar> oshyshko: i've used couchdb, not with haskell though
16:51 < rovar> once it gets security and better validation, it would be excellent to integrate directly into a front-end library like sproutcore
16:52 < rovar> it completely removes the web framework in the middle, which is nice
16:52 < rovar> I aim to use happstack as a better, faster, more secure, distributed couchdb
16:58 < rovar> frankly, it would take little effort to be faster and more secure.
16:59 < rovar> also, there is a front end, firerift that I wish to use as a basis for web applications using happstack
17:16 < solidsnack> rovar: in regards to your remarks late last night, about the the hit counter
17:16 < solidsnack> rovar: this is actually very similar to distributed logging
17:17 < solidsnack> the "programming language" of the hit counter only has one statement in it: `+1`
17:17 < solidsnack> likewise, the "logging language" has `>> string`
17:17 < solidsnack> so the system will store a bunch of statements in these languages
17:18 < solidsnack> simultaneous `+1` to the hit counter results in branches
17:18 < solidsnack> the voting will result in one branch being on the trunk
17:18 < solidsnack> but all the others are stored
17:18 < solidsnack> only the actual hits database knows that all this branching and voting was for nothing
17:19 < solidsnack> it just takes the revisions -- branches and trunk -- and adds them together; the hit counter language can not have conflicts
17:22 < solidsnack> same for apache logs
17:23 < solidsnack> when i called it a "consistent logging algorithm" i was thinking specifically of database logging
20:15 < rovar> is there a reason why deriveAll would conflict with  trying to make GuestBook an instance of (Typeable, Data) it says it's already defined, however I can't seem to use the appropriate methods
20:16 < stepcut> rovar: deriveAll allows derives Data and Typeable
20:16 < rovar> that was my guess.... but unless Text.JSON creates its own forms of Data and Typeable, I should be able to use encodeJSON
20:17 < rovar> no wait.. that's not my problem.. nevermind
20:18 < rovar> there is an instance for Data, but not Data (m r)
20:18 < rovar> i don't think it likes the newtype...
20:19 < rovar>     No instance for (Data (m r))
20:19 < rovar>       arising from a use of `encodeJSON' at src/AppState.hs:38:21-34
20:19 < rovar>     Possible fix: add an instance declaration for (Data (m r))
20:23 < rovar> arg.. i think i see the problem, but this is at the edge of my haskell prowess
20:24 < stepcut> :)
20:35 < rovar> readJSONGuestBook needs to return a string.
20:35 < rovar> however, I'm not sure how to query for the GuestBook so that I can encode it to a JSON String
20:53 < rovar> orly?
21:03 < rovar> stepcut: is there a runQuery or something for which I could retrieve a GuestBook value from readGuestBook?
21:30 < stepcut> rovar: do gb <- query ReadGuestBook ; ...
21:31 < stepcut> ?
21:32 < rovar> sure, I'm just trying to figure out how I can run that in the monad and return a String
21:32 < rovar> readJSONGuestBook :: String
21:32 < rovar> readJSONGuestBook = do gb <- query ReadGuestBook
21:32 < rovar>                        encodeJSON gb
21:32 < rovar> -->  No instance for (Control.Monad.Trans.MonadIO [])
21:34 < rovar> i guess i could make that IO String, and return $ encodeJSON gb
21:35 < stepcut> reading the state is not a pure operation
21:35 < rovar> yea, I gather reading from a DB in nondeterministic :)
21:36 < rovar> i knew that, but for some reason i try to make things harder than they are
21:36 < stepcut> rovar: :)
21:40 < rovar> is there an easy way to find the type of dir?
21:41 < stepcut> Prelude> :m + Happstack.Server
21:41 < stepcut> Prelude Happstack.Server> :t dir
21:41 < stepcut> dir :: (ServerMonad m, Control.Monad.MonadPlus m) => String -> m a -> m a
21:42 < rovar> how are both of those type m?
21:42 < rovar> rather, how is m both types?
21:44 < solidsnack> rovar: so, actually, m is a type in both typeclasses
21:44 < rovar> is see
21:46 < solidsnack> dir has a type (String -> m a -> m a) such that (m is in ServerMonad) and (m is in Control.Monad.MonadPlus) and (a is in the set of all types)
21:46 < solidsnack> typeclasses are sort of like interfaces or abstract baseclasses
21:47 < solidsnack> they define behaviour but you don't have concrete instances of them
21:47 < solidsnack> you have instances of types that implement them
21:47 < rovar> right
21:48 < rovar> I just think of Monads as function containers,  they make sense to me as concrete instances
21:50 < solidsnack> hmm
21:50 < rovar> is it possible to iterate over all of the elements of a record if they're all the same type?
21:50 < solidsnack> no
21:50 < rovar> damn
21:50 < solidsnack> yeah
21:51 < stepcut> I just think of monads as an endofunctors with two associated natural transformations...
21:52 < rovar> but how could an instance of two different Monads transform? which transformations would it use?
21:53 < solidsnack> stepcut: oh, haha
21:53 < stepcut> rovar: what do you mean by 'an instance of two different Monads transform' ?
21:54 < solidsnack> rovar: so, this is actually not as hard as it looks
21:54 < solidsnack> m is an instance of two different typeclasses
21:54 < solidsnack> these typeclasses happen to be monads
21:54 < rovar> do they define an intersecting set of functions?
21:55 < solidsnack> oh, i see what you are after
21:55 < solidsnack> they can not do that, no
21:55 < rovar> oh
21:55 < rovar> well that's fine then
21:55 < solidsnack> the monadic part is defined in the typeclass Monad
21:56 < solidsnack> so here will have some sort of familiar terminology: there is no "sub-typing" in Haskell but there is sub-classing; every ServerMonad must also be in Monad
21:56 < solidsnack> there is no way to override the Monad stuff, though
21:57 < rovar> so what is MonadPlus?
21:57 < rovar> ahh. mzero and mplus
21:57 < solidsnack> MonadPlus is Monad with additional operations for appending
21:57 < solidsnack> write
21:57 < solidsnack> s/write/right/
21:58 < solidsnack> i think there was a time when i longed to be able to override superclass methods in a subclass; but i now i see that as the door to insanity :)
21:58 < stepcut> :)
21:59 < stepcut> so, there is another way of explaining that type signature. Let's say that the type signature was:
21:59 < stepcut> dir :: String -> m a -> m a
22:00 < stepcut> in that case, 'm' could be an type that has a single type variable. For example, data Identity a = Identity a, data Maybe a = Just a  | Nothing, etc
22:01 < stepcut> but, we can also add class constraints (i think that is the right term). Like, dir :: (Monad m) => String -> m a -> m a
22:01 < solidsnack> stepcut: that is the received terminology, yes -- class constraints
22:02 < stepcut> that just adds an extra requirement that we can use any 'm' that takes a single type variable, provided there is also an instance of Monad  for the type.
22:02 < stepcut> aka, instance (Monad Identity) where ..., instance Monad Maybe where, etc
22:03 < rovar> gotcha
22:04 < solidsnack> now, fun fact -- you remember i said that you can't have overlapping definitions of the functions?
22:04 < stepcut> there are lots of different type classes, and types can belong to lots of different type classes, so we can list multiple constraints like
22:04 < stepcut> (MonadPlus m, ServerMonad m) =>
22:04 < solidsnack> so if you use the function that belongs to Monad, the system can infer that there is a Monad constraint
22:04 < stepcut> all that does is restrict 'm' to types that also have instances for those classes
22:08 < rovar> sure
22:36 < rovar> sleepy time
22:36 < rovar> &
--- Log closed Mon Mar 02 00:00:28 2009